Skip to content
E.Wright design systems
v1.0.0One component contract. Two materials.

Porcelain

Bright surfaces. Precise controls. Room to focus.

The material contract

Porcelain is the product surface. Paper is the wireframe surface. Structure, content and behavior carry across both.

Canvas
Surface
Action
01 / Foundations

A small set of clear decisions.

Use semantic tokens for purpose, not raw colors in component code. Change the theme at the root or on a contained surface.

Color & contrast

Download tokens ↓

Measured ratios use solid token colors. Every body-text pairing is checked against 4.5:1; focus and control boundaries against 3:1. Texture, imagery and local overrides still need review.

Semantic palette — current theme
TokenValueUseContrast

Typography

Inter, with the system sans-serif as fallback. 400 for reading; 500 for labels; 600 for hierarchy.

Aa · Display44 / 53 · page introductionSection heading32 / 38 · sectionCard heading24 / 29 · groupingBody text stays readable.16 / 26 · readingLabels and useful metadata14 / 20 · interfaceSECONDARY CAPTION12 / 17 · secondary only

Use sentence case. Keep paragraphs under 65 characters per line where practical. Never shrink essential content to fit.

Space & shape

4px base rhythm. Use 8–12px inside a control, 16–24px between related content, and 32–64px between sections.

8Control24Pill

Porcelain controls use 10px corners; Paper controls use 24px. Content panels use 24px in both.

Elevation & material

00 · Flat
01 · Control
02 · Panel
03 · Overlay

Porcelain uses ambient shadows. Paper uses directional shadows and subtle grain. Keep text on opaque surfaces. Shadows decorate; labels, outlines and structure communicate state.

Motion & iconography

20px icons on a 24-unit grid. 1.8-unit strokes, round caps and joins. Place icons before labels; use arrows for direction.

  • 120ms — hover and pressed feedback.
  • 180ms — local control changes.
  • 240ms — larger surface transitions.
  • Reduced motion — animation and transitions stop.

Icon-only controls require an accessible name and a 44px target. Decorative icons remain hidden from assistive technology.

Responsive layout

RangeLayoutBehavior
Compact · below 40remOne column, 20px guttersStack fields and actions; maintain 44px touch targets.
Medium · 40–60remFlexible two-column contentLet labels wrap. Keep navigation reachable without hover.
Wide · above 60remSidebar + fluid main areaKeep long reading content at 65ch and work areas within 80rem.
Attachment card · below 30remContainer queryMove Add/Remove below the document, even in a wide viewport.

At 200% zoom, content should reflow. A data table may scroll inside a named region; the page itself should not require horizontal scrolling.

02 / Component library

Primitives that work together.

These are live HTML components using the downloadable styles and behavior module. The examples use local sample data.

Buttons & actions

.ew-button

One primary action per task group. Use a verb and an object. Links navigate; buttons change state. Loading keeps its label and size. Explain why an action is unavailable nearby.

Markup & state contract
<button class="ew-button" data-variant="primary" type="submit">
  Review claim
</button>

Variants: primary, secondary (default), quiet, danger. States: default, hover, focus-visible, active, disabled, busy. Add data-size="large" for a 52px target. Disabled buttons use native disabled; loading adds aria-busy="true".

Inputs & selection

Use the name shown on the account.

! Enter a complete email address, such as erika@example.com.

Optional · up to 240 characters. Avoid private information.

Choose an account before assigning a team.

Choice controls

Evidence to include
Review priority
When should I use a switch?

For a setting applied immediately. Use a checkbox for a selection that will be submitted with a form.


Validation rules

  • Labels stay visible when fields have values.
  • Use a hint before an error occurs; name the remedy when it does.
  • Validate on submit, then recheck changed invalid fields.
  • Preserve entered values. Focus the first invalid field.
  • Connect errors with aria-describedby and aria-invalid.
  • Use native date, number and select controls unless the task requires a custom picker.

Status & feedback

Draft✓ Ready! Review! Missingi Received
Details saved.
Your changes are ready for review.
Evidence needs attention.
Add an invoice before continuing.
Couldn’t save your changes.
Your input is preserved. Try again.
Review is not approval.
A reviewer will check eligibility separately.

Pair every color with a label or symbol. Use a live region only for a new event, not every static status. Critical errors stay near the affected task.

Navigation & tabs

Invoice DEMO-1042 · one product · $100.00.

Sample invoice attached. No file has been uploaded.

This local example has not been submitted.

Tab enters the selected tab. Arrow keys move between tabs; Home and End jump to either edge. Panels activate immediately because their content is already available.


  1. Details
  2. Evidence
  3. Review

Steps describe workflow progress. They are links only when returning to a step is safe and supported.

Disclosure & contextual help

What belongs in an accordion?

Supporting content that can be read independently. Keep primary actions, essential instructions and errors visible outside it.

Can several sections remain open?

Yes. Independent native disclosures let people compare content without repeatedly opening and closing sections.

More resources ▾

This is a disclosure containing ordinary links, not an ARIA menu. Tab follows the links; Escape closes the popover and returns focus to its trigger.

Dialogs & side sheets

Use a dialog for a focused decision. A sheet supports inspecting detail while keeping the current task in context.

Both use native modal dialogs: focus stays inside, Escape dismisses, and focus returns to the opening control. Destructive dialogs initially focus the safe action.

Dialog markup
<button data-ew-dialog="review">Review</button>
<dialog id="review" class="ew-dialog"
        aria-labelledby="review-title">
  <h2 id="review-title">Review changes</h2>
  <button data-ew-close autofocus>Close</button>
</dialog>

Table, sorting & pagination

Sample claims · local data only
OwnerStateAmount

Use real table headers and a caption. Keep numeric values aligned. Sort buttons expose direction with aria-sort. Scroll only the table when columns cannot fit.

Progress & loading

60%
Loading claim details

Show progress only when it can be measured. Skeletons reserve space and have one accessible loading label. Stop motion when reduced motion is requested.

Erika Wright

Designer · name remains visible

No evidence yet

Attach the invoice that supports this sale, then return to review.

Try the evidence pattern

Empty states explain what is missing and provide one useful next step.

03 / Composed patterns

A complete claim, in either material.

Try validation, evidence recovery and review. This example stays in the page: no file uploads, saved records or claim submissions.

  1. Details
  2. Evidence
  3. Review

Sale details

Invoice evidence

Keep the proof connected to the sale.

No invoice attachedUse a simulated invoice for this example.

No file is uploaded.

Keep the next step clear.
Use sample details, add the sample invoice, then review.

Pattern anatomy

  1. Orient. State the task, expected evidence and next step.
  2. Group. Put related fields together with persistent labels.
  3. Recover. Preserve values and name exactly what to correct.
  4. Review. Show the complete information before commitment.
  5. Confirm. Explain what happened and what happens next.

Material usage

Porcelain — product prototypes, participant tasks, review and operational interfaces.

Paper — structural studies, wireframes, task-flow exploration and annotated review.

Use the same layout and behavior when comparing them. Wireframe does not mean inaccessible or nonfunctional. Paper / dusk is an alternate light material, not a dark-mode promise.

04 / Inclusive behavior

Accessibility is part of the contract.

The library targets WCAG 2.2 AA. A system can provide sound defaults; conformance still depends on the complete product, content and integration.

Built into the primitives

  • Semantic labels, native form controls and meaningful DOM order.
  • Visible focus, with a 2px outline and 3px offset.
  • 44px minimum interactive targets, larger than the 24px WCAG minimum.
  • 4.5:1 regular text contrast; 3:1 essential non-text contrast.
  • Errors and statuses expressed through text as well as color.
  • Keyboard tabs, native dialog containment and focus return.
  • Reduced-motion and forced-color treatments.
  • Container-based attachment layout and wrapping filenames.

Release checks for each integration

  • Complete the task using only a keyboard.
  • Check at 320px and at 200% text enlargement.
  • Read labels, errors, dialogs and notifications with a screen reader.
  • Check native controls on Safari, Firefox and Chromium.
  • Confirm forced colors, reduced motion and long translated labels.
  • Verify focus is not obscured by sticky elements or notifications.
  • Test missing, invalid, loading, empty and failed-request states.
  • Validate again on the server before saving real data.

Reference guidance: WCAG 2.2, WAI-ARIA tabs, and modal dialog behavior. Automated checks do not replace assistive-technology testing.

05 / Implementation

Use the same code you see here.

Dependency-free CSS and ES modules. Bring your application logic; the library supplies visual tokens, states and a small interaction layer.

Extract the archive into your project. Serve its files from one folder. Import tokens before components, then choose a theme on the root.

<html lang="en" data-ew-theme="porcelain">
<link rel="stylesheet" href="./tokens.css">
<link rel="stylesheet" href="./components.css">
<body class="ew-system">
  <button class="ew-button" data-variant="primary">
    Continue
  </button>
  <script type="module">
    import { mount } from './components.mjs';
    const cleanup = mount(document);
    // Call cleanup() before unmounting this application island.
  </script>
</body>

Theming & extension

/* Same components, different material. */
[data-ew-theme="paper"] { /* neutral paper */ }
[data-ew-theme="paper-dusk"] { /* dimmer paper */ }

/* Override a semantic token within a scope. */
.billing-surface {
  --ew-content-max: 72rem;
}

Set the attribute before first paint to avoid a theme flash. Keep color-scheme: light for all three appearances. Never override an individual component with a raw color when an existing semantic token fits.

In React, import CSS once, call mount(ref.current) inside an effect and return its cleanup. Let React own data and validation; do not let both React and this module control the same tabs or dialog.

Boundaries & ownership

  • tokens.json is the source for generated theme CSS.
  • components.css owns reusable visual states.
  • components.mjs owns tabs, modal launchers, disclosures, copying and notices.
  • reference.mjs owns local examples only; do not ship it as application logic.
  • legacy-tokens.css bridges the current portfolio studies to the same palette.
  • Authentication, authorization, uploads and persistence belong to the consuming application.

Versioning & contribution

1.0.0 · September 21, 2026 — First shared Porcelain and Paper contract, including Paper / dusk, foundational tokens, native components, a responsive evidence pattern and integration guidance.

Use semantic versioning. A renamed token or changed interaction contract requires a major version. New compatible components or tokens use a minor version. Fixes use a patch version.

For a change, record the problem, affected components and migration; update the source tokens, rebuild generated CSS, run the included tests and review all appearances. Component names and semantic roles are the stable API.

Review the example

This dialog contains local sample content. Closing it returns you to the same point in the component library.

Delete this example?

This demonstrates a destructive confirmation. It does not delete portfolio content or stored records.

Claim details

i Sample data

Invoice DEMO-1042

Amount: $100.00

A side sheet is the same accessible dialog primitive, placed beside the work area.

Ready to review