Everything in its place.
A surface supports the task. Type establishes hierarchy. Color explains state.
Bright surfaces. Precise controls. Room to focus.
A surface supports the task. Type establishes hierarchy. Color explains state.
Porcelain is the product surface. Paper is the wireframe surface. Structure, content and behavior carry across both.
Use semantic tokens for purpose, not raw colors in component code. Change the theme at the root or on a contained surface.
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.
| Token | Value | Use | Contrast |
|---|
Inter, with the system sans-serif as fallback. 400 for reading; 500 for labels; 600 for hierarchy.
44 / 53 · page introductionSection heading32 / 38 · sectionCard heading24 / 29 · groupingBody text stays readable.16 / 26 · readingLabels and useful metadata14 / 20 · interfaceSECONDARY CAPTION12 / 17 · secondary onlyUse sentence case. Keep paragraphs under 65 characters per line where practical. Never shrink essential content to fit.
4px base rhythm. Use 8–12px inside a control, 16–24px between related content, and 32–64px between sections.
Porcelain controls use 10px corners; Paper controls use 24px. Content panels use 24px in both.
Porcelain uses ambient shadows. Paper uses directional shadows and subtle grain. Keep text on opaque surfaces. Shadows decorate; labels, outlines and structure communicate state.
20px icons on a 24-unit grid. 1.8-unit strokes, round caps and joins. Place icons before labels; use arrows for direction.
Icon-only controls require an accessible name and a 44px target. Decorative icons remain hidden from assistive technology.
| Range | Layout | Behavior |
|---|---|---|
| Compact · below 40rem | One column, 20px gutters | Stack fields and actions; maintain 44px touch targets. |
| Medium · 40–60rem | Flexible two-column content | Let labels wrap. Keep navigation reachable without hover. |
| Wide · above 60rem | Sidebar + fluid main area | Keep long reading content at 65ch and work areas within 80rem. |
| Attachment card · below 30rem | Container query | Move 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.
These are live HTML components using the downloadable styles and behavior module. The examples use local sample data.
.ew-buttonOne 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.
<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".
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.
For a setting applied immediately. Use a checkbox for a selection that will be submitted with a form.
aria-describedby and aria-invalid.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.
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.
Steps describe workflow progress. They are links only when returning to a step is safe and supported.
Supporting content that can be read independently. Keep primary actions, essential instructions and errors visible outside it.
Yes. Independent native disclosures let people compare content without repeatedly opening and closing sections.
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.
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.
<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>| Owner | State | Amount |
|---|
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.
Show progress only when it can be measured. Skeletons reserve space and have one accessible loading label. Stop motion when reduced motion is requested.
Designer · name remains visible
Attach the invoice that supports this sale, then return to review.
Try the evidence patternEmpty states explain what is missing and provide one useful next step.
Try validation, evidence recovery and review. This example stays in the page: no file uploads, saved records or claim submissions.
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.
The library targets WCAG 2.2 AA. A system can provide sound defaults; conformance still depends on the complete product, content and integration.
Reference guidance: WCAG 2.2, WAI-ARIA tabs, and modal dialog behavior. Automated checks do not replace assistive-technology testing.
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>/* 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.
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.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.