j3w1 / theme

j3w1 / theme4.0.0

j3w1 / command

  • SPEC Overview
  • SPEC Foundations
  • SPEC Components
  • SPEC Patterns
  • SPEC Tokens
  • SPEC Tools
  • SPEC Workbench
  • SPEC Form builder
  • SPEC Task kit
  • SPEC Recipes
  • SPEC Figma bridge
  • SPEC Report an issue
  • SPEC Implement
  • SPEC For agents
  • SPEC Ports
  • SPEC Releases
  • SPEC Specification
  • DEMO Vue application demo

j3w1 UI Theme Spec

Identity, role tables, component index, accessibility and portability rules. Full state matrices, contrast pairs and decisions have dedicated static pages.

Source revision 9afef8564142e41458748895d16b4df161a67d66

Families (all shown by default)

Identity

What the j3w1 theme is, where it came from, and the five rules that keep a port recognisable.

True-black canvas, editor and terminal interiors (#000000), neutral near-black panels and raised layers, rose interface text and terminal/agent prose, and distinct syntax and status hues (D-041). Red marks identity, focus, selection and danger; ordinary application content and terminal prose use rose; white is reserved for document headings, exceptional highlights and contrast-critical roles. Keep 1px square borders, zero radii and one monospace family for chrome, reading and code. Darkness is the canvas; readable content is the priority.

Five rules keep an implementation recognisable:

  1. Preserve the true-black base, rose application and terminal text hierarchy and restrained red identity. Use semantic colours to distinguish code, additions, warnings and information.
  2. Use the role assigned to a token, never the token whose colour happens to look closest.
  3. Keep content, selection, keyboard focus, diagnostics and changed text distinguishable from one another. Selection is a fill; focus is a ring.
  4. Nothing is rounded, blurred, glowing or gradient-filled. Elevation is a 1px border and, for modals, a backdrop.
  5. Preserve the host application’s behaviour, keyboard handling and accessibility settings. Geometry and typography limits of a host are documented deviations, not reasons to rewrite it.

Where it came from

The palette began on a Manjaro i3 workstation (j3w1/1w3j): a pywal ramp from a red wallpaper, frozen and tuned slot by slot in config/Xresources. The i3 configuration gave the rest: 1px borders, 14/−2 gaps, tabbed layouts, dunst toasts framed in #ae1914, dmenu selections in #630f0d. Its web version, j3w1/j3w1.github.io, named the roles this specification uses and wrote the first contrast contract. Both are pinned in references/sources.json. This repository is the authority: later changes in either source are proposals, not automatic updates.

What “modern” means here

Clear structure, responsive layout, strong keyboard and screen-reader support, exact states, pleasant controls. Not pill buttons, glass panels, gradients, neon glows, a Material-style redesign, or red on every surface; the site draws such misreadings as labelled non-examples.

One exception (D-014): the generated preview beside each visible CSS hex literal on the spec page. It adds no palette, role or geometry rule, and text, copying, keyboard order and no-JS access stay intact.

  • A 16px circle with its theme-derived 1px boundary; alpha shows over a checkerboard of theme tokens.
  • On CSS :hover it becomes a 17.4px square (fast duration, ease-out on transform and border-radius; none under reduced motion).
  • Mouse and pen pointers also open a non-interactive popup with the exact value; touch and unknown pointers do not. CSS :hover alone drives both, never the hover or any-hover media features, which can report no hover despite a mouse.
  • The popup follows the pointer inside the circle at an 8px gap, flips when needed and keeps an 8px viewport gutter. Tracking has no animation.
  • It closes when the pointer leaves the circle, on an outside press, Escape, loss of window focus, and on page or nested scrolling unless the circle is still under the last pointer position. It never captures input, holds itself open or adds a keyboard stop; token tables and the token inspector keep the persistent information.

Profiles

  • default — the approved everyday composition: true-black interiors, neutral application layers, rose application text and terminal/agent prose, red interaction accents, and semantic green, amber, blue, violet and cyan for coding and terminal content (D-041). code.syntax.* is coloured by default; code.hued.* remains the compatible semantic alias family for ports that already consume it.
  • heritage-ansi — the sixteen Xresources slots and their historical assignments, exact, including those that fail the contrast floor. For archives and fidelity, never new interface text.
  • extended — the earlier proposed, unapproved overlay for syntax, terminal and chart colours. D-041 updates the default directly; it does not promote this profile.

Naming

Roles are color.<group>.<role>, from a closed group list: surface, text, border, interaction, action, status, code, diagnostic, diff, terminal, chart, icon. Primitives are color.primitive.<family>.<step>, the step rising with luminance; roles alias primitives, and primitives carry provenance. A CSS custom property is the path with dashes for dots: color.interaction.focus.ring → --color-interaction-focus-ring.

Foundations

Surfaces, text ladder, borders, interaction states, focus, typography, spacing, density, elevation, motion, icons and layout, with the rules that govern each role.

Values live in tokens/; this document says what each role means and where it may be used. Every rule is normative for the default profile.

Surfaces

surface.desktop and surface.canvas are true black (#000000). Readable content sits on the canvas or on:

  • default (#0d0707) for panels and cards;
  • raised (#140b0b) for sticky headers, menus and popovers;
  • overlay (#1c1010) for dialogs and drawers;
  • accent (#3d0c0a) for the user’s own content set apart from its neighbours, such as outgoing chat messages; secondary text on it uses text.muted, never text.subtle. Red links cap its brightness: at this hue it stays at or below #3f0c0a (D-035);
  • sunken (#000000) for reading and detail panes;
  • input for form-control fills;
  • true-black chrome and warm rose-black chrome-alt for window frames and bars.

D-041 keeps ordinary application layers warm rose-black, without a cool blue cast; surface.accent remains a bounded red message surface, not a tint for every panel.

The layers differ only slightly, so controls also carry border.control. Never tint photos, video, document content or user-defined data colours.

Text ladder

RoleUse
text.proselong-form reading; aliases rose text.default
text.headingwhite document/content titles and H1–H6
text.highlightdeliberate exceptional white highlights
text.brightbrighter rose UI labels
text.defaultrose interface and body text
text.mutedsecondary text; the darkest colour permitted for ordinary chrome text
text.subtlemetadata, comments, line numbers
text.disableddisabled controls only (exempt under WCAG 1.4.3; at least 3:1 by policy)
text.accentrestrained red accent text on canvas and default surfaces
text.accent-strongred emphasis suitable for raised surfaces
text.linkunderlined links; hover uses text.link-hover on interaction.hover.bg

D-041 uses rose for ordinary application text and terminal/agent prose (text.default, #e99499); terminal prose and prompts use bright rose (terminal.fg, #ffa2a7) for clearer small text. White is limited to document headings, exceptional highlights and contrast-critical roles. Exact values and ratios per surface are in the token and contrast reports. Metadata and comments people need to read use text.subtle, never a decorative border or historical ANSI primitive.

Borders

Every border is 1px (border.width.default). 2px (border.width.emphasis) is only for the selected indicator bar, the sticky-header rule and the invalid border. The quote rule, which marks a block rather than bounding a control, is the one wider edge, at twice the emphasis width.

  • border.divider (#482b2b) separates rows and sections.
  • border.default (#482b2b) is decorative, never the only visible edge of a control.
  • border.control (#c81a1a) is the edge of every form control at rest.
  • border.active (#e53935) marks the focused or active control.
  • border.overlay (#c81a1a) frames every floating layer.

Styles: solid by default; dashed only for focus, drop targets and read-only fields; dotted for hints; double for conflicts. Radius is 0 everywhere, including checkboxes, switches, chips, avatars, badges and tooltips.

Interaction states

Every interactive component declares which of these apply and demonstrates every applicable one, including the combinations. Precedence when several apply: disabled > loading > invalid > selected > pressed > hover; focus-visible is always drawn on top and never suppressed by another state.

StateVisualNon-colour channel
defaultrest tokens—
hover (@media (hover: hover) only)background → interaction.hover.bg; links use it too with text.link-hover, menu items → interaction.hover.bg-stronglink underline thickens 1px → 2px; cursor
active / pressedbackground → interaction.pressed.bg; border → border.activeborder change; no translation
focus-visiblethe ring (below)the ring itself; never a glow or a colour shift alone
selectedfill interaction.selection.bg with interaction.selection.text; tabs and navigation use a 2px border.selected-indicatoraria-selected / aria-current; a check glyph in lists
selected + focus-visiblethe selection fill and the ordinary ring (rule 1; D-027)both visible at once
text selected, host keeps the text colourtranslucent interaction.text-selection.tint (D-036), which also suits hosts that paint the fill over their content; where the host can recolour selected text, interaction.text-selection.bg with interaction.text-selection.textthe host’s selection handles
selected, container inactiveinteraction.selection.inactive-bg with interaction.selection.inactive-text; no ringlightness drop between the two fills
disabledtext.disabled, border.disabled, interaction.disabled.bg; no hover or pressed styling; still focusable when aria-disableddisabled / aria-disabled; cursor: not-allowed (rule 5)
invalidborder → status.danger.border at 2px; message in status.danger.text with the ✕ glyph; aria-invalid; aria-describedbyborder width 1 → 2px; glyph; message
invalid + focus-visiblethe 2px danger border and focus.ring-contrast at focus.offset-invaliddouble boundary
read-onlytext.default; 1px dotted border.divider bottom; no fill; focusable; selectablereadonly; dotted edge
loadingsize unchanged; a static ⋯ glyph replaces the leading icon; aria-busyglyph; no animation under reduced motion
busy / indeterminatestatic 45° stripes of action.primary.bg on interaction.pressed.bg; aria-valuetextstripes
checked / mixedfill action.primary.bg, glyph ✓ or – in action.primary.textglyph
expanded / collapsedSVG chevron rotated 0 / 90° within the motion budgetaria-expanded
current2px border.selected-indicator and text.brightindicator bar
drop-target / draggingdashed interaction.drop-target border; interaction.marquee filldashed pattern

Rules that apply everywhere:

  1. Selection is a fill; focus is a ring. Neither borrows the other’s form. The ring must reach 3:1 on whatever it sits over: #e53935 falls below it on action.primary.bg and status.danger.fill, so the ring recolours on those fills; it meets it on interaction.selection.bg (D-027), so a selected row keeps the ordinary control ring.
  2. Focus ring (D-006; component mapping clarification D-015). Controls and rows: outline: 1px dashed {color.interaction.focus.ring}; outline-offset: -2px. Focusable containers (panes, windows, dialogs, cards): outline: 2px solid {color.interaction.focus.ring-container}; outline-offset: -3px. On filled surfaces use the component’s explicit ring mapping: primary buttons and checked controls use focus.ring-contrast (the control ring in interaction.focus.ring-container, D-040) where declared; destructive buttons use their declared on-fill text role. The selection fill is the exception and takes the ordinary ring, on the measurement in rule 1. Keep the control or container geometry independently of the colour mapping. :focus:not(:focus-visible) draws nothing. Forced-colors mode uses Highlight. A host focus indicator is never removed without this replacement.
  3. Never colour-only. Every state and every status carries a second channel: a glyph (✕ ! ✓ i ·), a border width, an underline pattern, or an ARIA state. Charts carry pattern fills.
  4. Hover changes fills and borders, never text colour alone, and only on hover-capable pointers.
  5. Disabled never uses opacity. Opacity leaks the background and breaks contrast accounting.
  6. Contrast floor. Text ≥ 4.5:1 and control boundaries, rings and meaningful graphics ≥ 3:1 against the actual background of the state, measured after compositing translucent colours.
  7. Motion. Durations are 80 / 120 / 150 ms at most, on opacity, transform and background only; under prefers-reduced-motion: reduce every duration is 0.01 ms, nothing slides or shimmers, and no behaviour waits on transitionend.

Actions

Four button tones:

  • primary, the only filled button at rest: action.primary.bg (#7d1310) with action.primary.text (bright rose; D-041).
  • secondary, an outline: border.control, text text.bright.
  • tertiary, a ghost or icon button: text.default, hover interaction.hover.bg.
  • destructive, an outline in action.destructive.text (#f73f35) that fills on hover with action.destructive.hover-bg (#dc282e) and #f9faf9 text. A filled variant exists for confirm dialogs.

Destructive actions also need a confirmation step or an undo; the colour is not the safeguard.

Status, diagnostics and diffs (D-001)

D-041 updates the palette while preserving the D-001 semantic roles.

Five statuses: red danger, amber warning, green success, blue info, and grey neutral. Each has text, fill, on-fill, tint and border roles, a required glyph (✕ ! ✓ i ·) and its own underline or border pattern (wavy, dashed, solid, dotted, double). Use the explicit on-fill role on a status fill, not ordinary body text. Coding and terminal roles also have violet and cyan; these distinguish syntax and named terminal colours rather than tinting ordinary application chrome. Every use follows its role and measures contrast on the actual surface.

Diagnostics:

  • error: wavy #e53935 underline, #f73f35 text, #e53935 stripe, #2b0e0d line background;
  • warning: wavy amber;
  • info: dotted blue;
  • hint: dotted text.subtle;
  • unused: text.muted with a dotted underline.

Diffs:

  • added: #0f1a0e line background, green gutter mark and +; word-level additions as a 2px green underline (no fill, so text contrast is untouched);
  • removed: #2b0e0d background, red gutter mark and −; word-level removals underlined and struck through;
  • modified: #1f1a0c background, amber gutter mark and ~;
  • conflicts: a double #f73f35 border.

Always keep textual markers and existing status icons.

Code and terminal

The surface and interior roles remain distinct in scope, but D-041 makes surface.code, surface.terminal, code.bg, code.gutter-bg, terminal.bg and default ANSI 0 all true black (#000000). This replaces the earlier #0c0909 interior assignment without changing historical ANSI primitives.

Editor surfaces:

  • code.current-line uses the neutral default layer;
  • code.line-number uses the readable subtle tier; active numbers and the caret step up to the normal and bright text tiers;
  • code.selection-bg is a subdued red selection fill;
  • code.search-match-bg marks matches, with the current match inverted by code.search-current-bg and code.search-current-text;
  • code.bracket-match is a 1px accent border;
  • code.indent-guide is a neutral separator and code.whitespace is a decorative neutral mark.

Syntax in default is semantic: violet keywords, green strings, amber numbers/constants/attributes/escapes, blue functions, cyan types/properties, coral tags/invalid text, rose variables/operators, muted punctuation and subtle italic comments. Headings use the bright text tier. The existing code.hued.* roles resolve to the corresponding semantic syntax assignments; ports need no separate palette. Invalid text takes a wavy underline and deprecated text a line-through. Languages inherit these roles; a language-specific override needs a written reason. Selection and diff fills must be checked with the syntax foregrounds they retain.

Terminal slots:

  • heritage-ansi carries the sixteen Xresources slots exactly. color.primitive.ansi.* remains byte-for-byte historical; the heritage profile explicitly restores its historical slot and background assignments.
  • default uses the semantic sixteen (D-041): black, red, green, amber, blue, violet, cyan and rose, followed by their bright variants. Slots 7 and 15 both use bright rose #ffa2a7 for readable terminal text. Slot 0 is the true-black background; slots 1–15, including neutral bright black, target at least 4.5:1 on it. Slots 2 and 10 remain green so programs using ANSI additions can be read correctly.
  • extended remains a proposed overlay, not an approved alternative needed to obtain coloured syntax or terminal slots.

Programs choose the slots and may emit 256-colour or true-colour values that bypass them. A theme cannot repair host dimming or independently recolour text that shares a host theme key with a background. Port guides record those limits; Claude Code’s shared word-highlight and edit-summary keys are one example. Their dedicated diff.added.shared-word and diff.removed.shared-word roles balance summary-on-black and ordinary rose-on-highlight at about 3:1. These roles apply only where a host combines those two uses; they do not replace standard diff emphasis or relax the ordinary-text contrast floor. Syntax foregrounds require separate host review.

Typography

One family: SauceCodePro NFM (Source Code Pro in the Nerd Fonts build), falling back to Source Code Pro, Cascadia Mono, Consolas, Liberation Mono, DejaVu Sans Mono and monospace. The site records size-adjust metrics for the fallbacks; no font file is distributed. Weights 400 and 700, plus italic.

Scale (size/line-height in px): ui-sm 12/16, ui-md 13/18, ui-lg 14/20, reading 15/24, code 13/19, terminal 13/19 with −0.5px letter-spacing, h1 20/28 bold, h2 16/24 bold, h3 13/18 bold in text.heading, caption 11/16 only with text.muted or lighter. D-037: display 32/40 for page heroes and metric figures and title 24/32 for page titles above h1; components keep h1–h3. Hosts keep the size the user chose; tiny UI text is a metric of the reference implementation, not a rule.

Spacing and density (D-009)

Spacing steps: 0, 1, 2, 4, 8, 12, 16, 24, 32, 48 px. compact is the default density (D-038): it applies wherever no data-density is set, in components, the site and copied bundles. Set data-density="comfortable" on any subtree to opt in to the larger mode:

ModeControlRowTypeHorizontal paddingGapsUse
compact24px28pxui-sm8px2pxmatches the workstation
comfortable32px36pxui-md12px4pxeveryday applications

Both meet the 24×24 CSS-pixel target minimum; compact needs 4px between neighbouring targets. Table rows always use the comfortable row height (a data row is content, and compact rows are harder to scan); controls inside a row follow the page density. The site’s 3px i3 gap, 14/−2 window gaps and 28px bar are window-manager geometry, not theme tokens.

Elevation and layering

No shadows, except shadow.floating (0 6px 22px rgb(0 0 0 / 55%)) on the i3 floating-window specimen. A floating layer is a 1px border.overlay on surface.raised; a modal adds surface.backdrop (rgb(0 0 0 / 65%)). Stacking: canvas 0 < raised 1 < popover 10 < drawer 20 < dialog 30 < toast 40 < skip link 1000.

A popup opened by hovering follows the pointer:

  • It sits 8px from the cursor, flips to the cursor’s other side instead of crossing a viewport edge, and keeps 8px from every edge.
  • It moves again on pointer move, scroll and resize.
  • A popup with nothing to operate takes no pointer events; one with a control or link stays reachable and open while the pointer is inside it.
  • Either kind closes when the pointer leaves both the trigger and the popup; the reachable kind waits 300 ms first, so the pointer can cross between them, and stays while keyboard focus is on its trigger or inside it.

Opened from the keyboard, the same popup anchors to its trigger: below it, or above when there is no room below. This is a placement rule only; what opens a popup and what kind it is belong to the component’s contract.

Icons

SVG line icons on a 16px grid, 1.5px stroke, stroke: currentColor, fill: none, sizes 12 / 16 / 20. No icon font is needed; Nerd Font glyphs appear only in terminal and heritage specimens. Icon-only controls carry aria-label and a tooltip. icon.decorative (#986f72) is for glyphs that mean nothing on their own.

Layout

Reading measure 72ch, content column 680px, application layout 1440px. Breakpoints 320 (reflow floor), 600, 900, 1280.

  • Components use container queries.
  • Sidebars collapse to drawers below 900px.
  • Data tables scroll horizontally, with a sticky first column, below 600px.
  • The page never scrolls horizontally at 320px.
  • Right-to-left mirrors breadcrumb separators, pagination, sidebar and drawer sides, wizard progression, affixes and tree indentation.

Typography semantics (D-033)

All content titles and H1–H6 use text.heading; size, weight and spacing carry the hierarchy. Chrome and window titles use text.default or text.bright; body and long-form prose use text.default and text.prose. Bold inherits the current semantic colour, including inside headings, muted text, links and selections, and never requests white by itself. D-041 keeps ordinary application text and brighter UI labels rose, with white reserved for document headings, exceptional highlights and contrast-critical roles. Terminal and agent prose uses rose terminal.fg; the semantic hierarchy and inherited bold rule remain. Selection and on-fill roles are explicit and must be measured against their actual backgrounds. The historical D-033 migration audit is docs/rose-typography-migration.md.

Tokens

Eligibility: use within the role's scope; use-and-report records its pending decision; blocked excludes delivery; historical-only preserves heritage; preview-only excludes delivery. Approval and consumption eligibility stay separate.

All profile values, primitives and documented usage →

Surfaces

desktop #000000--color-surface-desktopobserveduse
canvas #000000--color-surface-canvasapproveduse
chrome #000000--color-surface-chromeapproveduse
chrome-alt #140b0b--color-surface-chrome-altapproveduse
sunken #000000--color-surface-sunkenapproveduse
default #0d0707--color-surface-defaultapproveduse
raised #140b0b--color-surface-raisedapproveduse
overlay #1c1010--color-surface-overlayapproveduse
accent #3d0c0a--color-surface-accentapproveduse
input #000000--color-surface-inputapproveduse
backdrop rgb(0 0 0 / 65%)--color-surface-backdropproposeduse-and-reportD-008
code #000000--color-surface-codeapproveduse
terminal #000000--color-surface-terminalapproveduse

Text

default #e99499--color-text-defaultapproveduse
bright #ffa2a7--color-text-brightapproveduse
prose #e99499--color-text-proseapproveduse
muted #d4868b--color-text-mutedapproveduse
subtle #bd787d--color-text-subtleapproveduse
disabled #a3676b--color-text-disabledapproveduse
placeholder #bd787d--color-text-placeholderapproveduse
accent #e53935--color-text-accentobserveduse
accent-strong #f73f35--color-text-accent-strongobserveduse
on-selection #f4eeee--color-text-on-selectionobserveduse
on-action #ffa2a7--color-text-on-actionapproveduse
on-danger #f9faf9--color-text-on-dangerobserveduse
on-light #000000--color-text-on-lightapproveduse
inverse #000000--color-text-inverseapproveduse
heading #f4eeee--color-text-headingapproveduse
highlight #f4eeee--color-text-highlightapproveduse

Text ladder on each surface

Measured ratios; ordinary text needs 4.5:1, disabled text is exempt but held to 3:1.

surface.canvas
text.prose9.16:1
text.bright10.98:1
text.default9.16:1
text.muted7.58:1
text.subtle6.15:1
text.accent4.97:1
text.accent-strong5.72:1
surface.default
text.prose8.72:1
text.bright10.45:1
text.default8.72:1
text.muted7.22:1
text.subtle5.85:1
text.accent4.73:1
text.accent-strong5.44:1
surface.raised
text.prose8.46:1
text.bright10.14:1
text.default8.46:1
text.muted7.00:1
text.subtle5.68:1
text.accent4.59:1
text.accent-strong5.28:1

Selection is a fill; focus is a ring

The four combinations every list, table and tab strip must show. Focus rings on fills take the on-fill text colour.

plain row
hovered row
focused row (ring only)
selected row (fill only)
selected + focused row (fill and on-fill ring)
selected while the container is not focused

Borders and radii

divider · decorative hairline between rows
default · decorative, never a control's only edge
control · every form control at rest (≥ 3:1)
active · focused or active control
strong · 2px rules
overlay · every floating layer
disabled
dashed · focus, drop target, read-only only

Status set

Each status has text, fill, tint and border roles and a mandatory glyph. The three extension hues (D-001) exist only here, in diagnostics, in diffs, in the opt-in code.hued syntax roles (D-030) and in the proposed overlay.

✕ danger text
✕ danger fill
✕ danger tint with border
! warning text
! warning fill
! warning tint with border
✓ success text
✓ success fill
✓ success tint with border
i info text
i info fill
i info tint with border
· neutral text
· neutral fill
· neutral tint with border

Terminal slots by profile

heritage-ansi carries the sixteen Xresources slots exactly; the approved default profile carries the readable heritage sixteen (D-029; slot 6 coral, D-032); the proposed extended overlay reassigns them. Use the page's profile control to switch specimens, or read the columns.

Slotdefaultheritage-ansiextended
ansi.0#000000#0c0909#0c0909proposed
ansi.1#f07178#c81a1a#e53935proposed
ansi.2#82d9a0#bd787d#86a46fproposed
ansi.3#e5c07b#d4868b#c9973fproposed
ansi.4#82b4ff#8c1212#7e9ebbproposed
ansi.5#c7a0e8#f73f35#b37175proposed
ansi.6#78d4d4#9e474a#bd787dproposed
ansi.7#ffa2a7#ffa2a7#e99499proposed
ansi.8#bd787d#7d1310#ad7175proposed
ansi.9#ff9095#ab1612#f73f35proposed
ansi.10#a2edb8#ad2721#7fbf7aproposed
ansi.11#f2d49b#b37175#d6a24bproposed
ansi.12#a4caff#871f19#9ab3c9proposed
ansi.13#dec0f4#e82132#d4868bproposed
ansi.14#a0e7e7#e0292f#ffa2a7proposed
ansi.15#ffa2a7#a3676b#f4eeeeproposed

Borders

RoleCSS variableDefault valueStatus / eligibility
color.border.divider--color-border-divider#482b2bapproveduse
color.border.default--color-border-default#482b2bapproveduse
color.border.strong--color-border-strong#9e231fobserveduse
color.border.control--color-border-control#c81a1aapproveduse
color.border.active--color-border-active#e53935observeduse
color.border.overlay--color-border-overlay#c81a1aapproveduse
color.border.disabled--color-border-disabled#482b2bapproveduse
color.border.selected-indicator--color-border-selected-indicator#e53935observeduse
color.border.selected-indicator-inactive--color-border-selected-indicator-inactive#9e231fobserveduse

Interaction

RoleCSS variableDefault valueStatus / eligibility
color.interaction.focus.ring--color-interaction-focus-ring#e53935observeduse
color.interaction.focus.ring-container--color-interaction-focus-ring-container#ffa2a7observeduse
color.interaction.selection.bg--color-interaction-selection-bg#531310approveduse
color.interaction.selection.text--color-interaction-selection-text#f4eeeeobserveduse
color.interaction.selection.inactive-bg--color-interaction-selection-inactive-bg#420f0cobserveduse
color.interaction.selection.inactive-text--color-interaction-selection-inactive-text#e99499approveduse
color.interaction.text-selection.bg--color-interaction-text-selection-bg#420f0cobserveduse
color.interaction.text-selection.text--color-interaction-text-selection-text#f4eeeeobserveduse
color.interaction.text-selection.tint--color-interaction-text-selection-tintrgb(145 20 16 / 50%)approveduse
color.interaction.hover.bg--color-interaction-hover-bg#1c1010approveduse
color.interaction.hover.bg-strong--color-interaction-hover-bg-strong#1c1010approveduse
color.interaction.pressed.bg--color-interaction-pressed-bg#420f0cobserveduse
color.interaction.disabled.bg--color-interaction-disabled-bg#0d0707approveduse
color.interaction.marquee--color-interaction-marqueergb(145 20 16 / 12%)observeduse
color.interaction.drop-target--color-interaction-drop-target#e53935observeduse
color.interaction.scrollbar.track--color-interaction-scrollbar-track#000000approveduse
color.interaction.scrollbar.thumb--color-interaction-scrollbar-thumb#986f72approveduse
color.interaction.scrollbar.thumb-hover--color-interaction-scrollbar-thumb-hover#d4868bapproveduse

Actions

RoleCSS variableDefault valueStatus / eligibility
color.action.primary.bg--color-action-primary-bg#7d1310approveduse
color.action.primary.text--color-action-primary-text#ffa2a7approveduse
color.action.primary.hover-bg--color-action-primary-hover-bg#911410observeduse
color.action.primary.pressed-bg--color-action-primary-pressed-bg#630f0dobserveduse
color.action.primary.border--color-action-primary-border#9e231fobserveduse
color.action.secondary.bg--color-action-secondary-bgrgb(0 0 0 / 0%)observeduse
color.action.secondary.text--color-action-secondary-text#ffa2a7approveduse
color.action.secondary.border--color-action-secondary-border#986f72approveduse
color.action.secondary.hover-bg--color-action-secondary-hover-bg#630f0dobserveduse
color.action.secondary.pressed-bg--color-action-secondary-pressed-bg#420f0cobserveduse
color.action.tertiary.text--color-action-tertiary-text#e99499approveduse
color.action.tertiary.hover-bg--color-action-tertiary-hover-bg#1c0a09observeduse
color.action.destructive.text--color-action-destructive-text#f07178observeduse
color.action.destructive.border--color-action-destructive-border#e53935observeduse
color.action.destructive.hover-bg--color-action-destructive-hover-bg#dc282eobserveduse
color.action.destructive.hover-text--color-action-destructive-hover-text#f9faf9observeduse
color.action.destructive.pressed-bg--color-action-destructive-pressed-bg#ae1914observeduse
color.action.destructive.filled-bg--color-action-destructive-filled-bg#dc282eobserveduse
color.action.destructive.filled-text--color-action-destructive-filled-text#f9faf9observeduse

Status

RoleCSS variableDefault valueStatus / eligibility
color.status.danger.text--color-status-danger-text#f07178observeduse
color.status.danger.fill--color-status-danger-fill#dc282eobserveduse
color.status.danger.on-fill--color-status-danger-on-fill#f9faf9observeduse
color.status.danger.tint--color-status-danger-tint#2b0e0dobserveduse
color.status.danger.border--color-status-danger-border#e53935observeduse
color.status.warning.text--color-status-warning-text#e5c07bapproveduse
color.status.warning.fill--color-status-warning-fill#e5c07bapproveduse
color.status.warning.on-fill--color-status-warning-on-fill#000000approveduse
color.status.warning.tint--color-status-warning-tint#1f1a0capproveduse
color.status.warning.border--color-status-warning-border#e5c07bapproveduse
color.status.success.text--color-status-success-text#82d9a0approveduse
color.status.success.fill--color-status-success-fill#82d9a0approveduse
color.status.success.on-fill--color-status-success-on-fill#000000approveduse
color.status.success.tint--color-status-success-tint#0f1a0eapproveduse
color.status.success.border--color-status-success-border#82d9a0approveduse
color.status.info.text--color-status-info-text#82b4ffapproveduse
color.status.info.fill--color-status-info-fill#82b4ffapproveduse
color.status.info.on-fill--color-status-info-on-fill#000000approveduse
color.status.info.tint--color-status-info-tint#0f141capproveduse
color.status.info.border--color-status-info-border#82b4ffapproveduse
color.status.neutral.text--color-status-neutral-text#d4868bapproveduse
color.status.neutral.fill--color-status-neutral-fill#986f72approveduse
color.status.neutral.on-fill--color-status-neutral-on-fill#000000observeduse
color.status.neutral.tint--color-status-neutral-tint#140b0bapproveduse
color.status.neutral.border--color-status-neutral-border#986f72approveduse

Code

RoleCSS variableDefault valueStatus / eligibility
color.code.bg--color-code-bg#000000approveduse
color.code.current-line--color-code-current-line#0d0707approveduse
color.code.gutter-bg--color-code-gutter-bg#000000approveduse
color.code.line-number--color-code-line-number#bd787dapproveduse
color.code.line-number-active--color-code-line-number-active#e99499approveduse
color.code.gutter-rule--color-code-gutter-rule#482b2bapproveduse
color.code.caret--color-code-caret#ffa2a7approveduse
color.code.selection-bg--color-code-selection-bg#420f0cobserveduse
color.code.search-match-bg--color-code-search-match-bg#630f0dobserveduse
color.code.search-current-bg--color-code-search-current-bg#ffa2a7observeduse
color.code.search-current-text--color-code-search-current-text#000000approveduse
color.code.bracket-match--color-code-bracket-match#e53935observeduse
color.code.indent-guide--color-code-indent-guide#482b2bapproveduse
color.code.whitespace--color-code-whitespace#986f72approveduse
color.code.syntax.keyword--color-code-syntax-keyword#c7a0e8approveduse
color.code.syntax.string--color-code-syntax-string#82d9a0approveduse
color.code.syntax.comment--color-code-syntax-comment#bd787dapproveduse
color.code.syntax.number--color-code-syntax-number#e5c07bapproveduse
color.code.syntax.constant--color-code-syntax-constant#e5c07bapproveduse
color.code.syntax.function--color-code-syntax-function#82b4ffapproveduse
color.code.syntax.variable--color-code-syntax-variable#e99499approveduse
color.code.syntax.type--color-code-syntax-type#78d4d4approveduse
color.code.syntax.operator--color-code-syntax-operator#e99499approveduse
color.code.syntax.punctuation--color-code-syntax-punctuation#d4868bapproveduse
color.code.syntax.property--color-code-syntax-property#78d4d4approveduse
color.code.syntax.heading--color-code-syntax-heading#f4eeeeapproveduse
color.code.syntax.tag--color-code-syntax-tag#f07178approveduse
color.code.syntax.attribute--color-code-syntax-attribute#e5c07bapproveduse
color.code.syntax.escape--color-code-syntax-escape#e5c07bapproveduse
color.code.syntax.invalid--color-code-syntax-invalid#f07178approveduse
color.code.syntax.deprecated--color-code-syntax-deprecated#bd787dapproveduse
color.code.hued.string--color-code-hued-string#82d9a0approveduse
color.code.hued.number--color-code-hued-number#e5c07bapproveduse
color.code.hued.constant--color-code-hued-constant#e5c07bapproveduse
color.code.hued.function--color-code-hued-function#82b4ffapproveduse
color.code.hued.attribute--color-code-hued-attribute#e5c07bapproveduse
color.code.hued.escape--color-code-hued-escape#e5c07bapproveduse
color.code.hued.type--color-code-hued-type#78d4d4approveduse
color.code.hued.property--color-code-hued-property#78d4d4approveduse
color.code.hued.operator--color-code-hued-operator#e99499approveduse

Diagnostics

RoleCSS variableDefault valueStatus / eligibility
color.diagnostic.error.underline--color-diagnostic-error-underline#e53935observeduse
color.diagnostic.error.text--color-diagnostic-error-text#f73f35observeduse
color.diagnostic.error.stripe--color-diagnostic-error-stripe#e53935observeduse
color.diagnostic.error.bg--color-diagnostic-error-bg#2b0e0dobserveduse
color.diagnostic.warning.underline--color-diagnostic-warning-underline#e5c07bapproveduse
color.diagnostic.warning.text--color-diagnostic-warning-text#e5c07bapproveduse
color.diagnostic.warning.stripe--color-diagnostic-warning-stripe#e5c07bapproveduse
color.diagnostic.info.underline--color-diagnostic-info-underline#82b4ffapproveduse
color.diagnostic.info.text--color-diagnostic-info-text#82b4ffapproveduse
color.diagnostic.hint.underline--color-diagnostic-hint-underline#bd787dapproveduse
color.diagnostic.unused.text--color-diagnostic-unused-text#d4868bapproveduse

Diffs

RoleCSS variableDefault valueStatus / eligibility
color.diff.added.bg--color-diff-added-bg#0f1a0eapproveduse
color.diff.added.gutter--color-diff-added-gutter#82d9a0approveduse
color.diff.added.emphasis--color-diff-added-emphasis#82d9a0approveduse
color.diff.added.shared-word--color-diff-added-shared-word#2c6540approveduse
color.diff.removed.bg--color-diff-removed-bg#2b0e0dobserveduse
color.diff.removed.gutter--color-diff-removed-gutter#e53935observeduse
color.diff.removed.emphasis--color-diff-removed-emphasis#e53935observeduse
color.diff.removed.shared-word--color-diff-removed-shared-word#953d46approveduse
color.diff.modified.bg--color-diff-modified-bg#1f1a0capproveduse
color.diff.modified.gutter--color-diff-modified-gutter#e5c07bapproveduse
color.diff.conflict-border--color-diff-conflict-border#f73f35observeduse
color.diff.header-bg--color-diff-header-bg#241010observeduse

Terminal

RoleCSS variableDefault valueStatus / eligibility
color.terminal.bg--color-terminal-bg#000000approveduse
color.terminal.fg--color-terminal-fg#ffa2a7approveduse
color.terminal.cursor--color-terminal-cursor#ffa2a7approveduse
color.terminal.selection-bg--color-terminal-selection-bg#420f0cobserveduse
color.terminal.selection-text--color-terminal-selection-text#f4eeeeobserveduse
color.terminal.prompt-bg--color-terminal-prompt-bg#000000approveduse
color.terminal.prompt-text--color-terminal-prompt-text#ffa2a7approveduse
color.terminal.ansi.0--color-terminal-ansi-0#000000approveduse
color.terminal.ansi.1--color-terminal-ansi-1#f07178approveduse
color.terminal.ansi.2--color-terminal-ansi-2#82d9a0approveduse
color.terminal.ansi.3--color-terminal-ansi-3#e5c07bapproveduse
color.terminal.ansi.4--color-terminal-ansi-4#82b4ffapproveduse
color.terminal.ansi.5--color-terminal-ansi-5#c7a0e8approveduse
color.terminal.ansi.6--color-terminal-ansi-6#78d4d4approveduse
color.terminal.ansi.7--color-terminal-ansi-7#ffa2a7approveduse
color.terminal.ansi.8--color-terminal-ansi-8#bd787dapproveduse
color.terminal.ansi.9--color-terminal-ansi-9#ff9095approveduse
color.terminal.ansi.10--color-terminal-ansi-10#a2edb8approveduse
color.terminal.ansi.11--color-terminal-ansi-11#f2d49bapproveduse
color.terminal.ansi.12--color-terminal-ansi-12#a4caffapproveduse
color.terminal.ansi.13--color-terminal-ansi-13#dec0f4approveduse
color.terminal.ansi.14--color-terminal-ansi-14#a0e7e7approveduse
color.terminal.ansi.15--color-terminal-ansi-15#ffa2a7approveduse

Charts

RoleCSS variableDefault valueStatus / eligibility
color.chart.series-1--color-chart-series-1#ffa2a7observeduse
color.chart.series-2--color-chart-series-2#f73f35observeduse
color.chart.series-3--color-chart-series-3#bd787dobserveduse
color.chart.series-4--color-chart-series-4#a3676bobserveduse
color.chart.axis--color-chart-axis#9e231fobserveduse
color.chart.grid--color-chart-grid#2b0e0dobserveduse
color.chart.label--color-chart-label#d4868bapproveduse

Icons

RoleCSS variableDefault valueStatus / eligibility
color.icon.default--color-icon-default#e99499approveduse
color.icon.decorative--color-icon-decorative#986f72approveduse

Spacing

RoleCSS variableDefault valueStatus / eligibility
space.0--space-00pxobserveduse
space.1--space-11pxobserveduse
space.2--space-22pxobserveduse
space.4--space-44pxobserveduse
space.8--space-88pxobserveduse
space.12--space-1212pxobserveduse
space.16--space-1616pxobserveduse
space.24--space-2424pxobserveduse
space.32--space-3232pxobserveduse
space.48--space-4848pxobserveduse

Density

RoleCSS variableDefault valueStatus / eligibility
density.compact.control-height--density-compact-control-height24pxobserveduse
density.compact.row-height--density-compact-row-height28pxobserveduse
density.compact.control-padding-x--density-compact-control-padding-x8pxobserveduse
density.compact.icon--density-compact-icon12pxobserveduse
density.compact.gap--density-compact-gap2pxobserveduse
density.comfortable.control-height--density-comfortable-control-height32pxobserveduse
density.comfortable.row-height--density-comfortable-row-height36pxobserveduse
density.comfortable.control-padding-x--density-comfortable-control-padding-x12pxobserveduse
density.comfortable.icon--density-comfortable-icon16pxobserveduse
density.comfortable.gap--density-comfortable-gap4pxobserveduse

Border widths

RoleCSS variableDefault valueStatus / eligibility
border.width.default--border-width-default1pxobserveduse
border.width.emphasis--border-width-emphasis2pxobserveduse

Radius

RoleCSS variableDefault valueStatus / eligibility
radius.none--radius-none0pxobserveduse

Typography

RoleCSS variableDefault valueStatus / eligibility
font.family.mono--font-family-mono"SauceCodePro NFM", "Source Code Pro", "Cascadia Mono", "Consolas", "Liberation Mono", "DejaVu Sans Mono", monospaceobserveduse
font.weight.regular--font-weight-regular400observeduse
font.weight.bold--font-weight-bold700observeduse
font.size.ui-sm--font-size-ui-sm12pxobserveduse
font.size.ui-md--font-size-ui-md13pxobserveduse
font.size.ui-lg--font-size-ui-lg14pxobserveduse
font.size.reading--font-size-reading15pxobserveduse
font.size.code--font-size-code13pxobserveduse
font.size.terminal--font-size-terminal13pxobserveduse
font.size.display--font-size-display32pxapproveduse
font.size.title--font-size-title24pxapproveduse
font.size.h1--font-size-h120pxobserveduse
font.size.h2--font-size-h216pxobserveduse
font.size.h3--font-size-h313pxobserveduse
font.size.caption--font-size-caption11pxobserveduse
font.line-height.ui-sm--font-line-height-ui-sm16pxobserveduse
font.line-height.ui-md--font-line-height-ui-md18pxobserveduse
font.line-height.ui-lg--font-line-height-ui-lg20pxobserveduse
font.line-height.reading--font-line-height-reading24pxobserveduse
font.line-height.code--font-line-height-code19pxobserveduse
font.line-height.terminal--font-line-height-terminal19pxobserveduse
font.line-height.display--font-line-height-display40pxapproveduse
font.line-height.title--font-line-height-title32pxapproveduse
font.line-height.h1--font-line-height-h128pxobserveduse
font.line-height.h2--font-line-height-h224pxobserveduse
font.line-height.h3--font-line-height-h318pxobserveduse
font.line-height.caption--font-line-height-caption16pxobserveduse
font.letter-spacing.terminal--font-letter-spacing-terminal-0.5pxobserveduse

Focus

RoleCSS variableDefault valueStatus / eligibility
focus.ring--focus-ring1px dashed #e53935observeduse
focus.ring-container--focus-ring-container2px solid #ffa2a7observeduse
focus.ring-contrast--focus-ring-contrast1px dashed #ffa2a7approveduse
focus.offset--focus-offset-2pxobserveduse
focus.offset-container--focus-offset-container-3pxobserveduse
focus.offset-invalid--focus-offset-invalid-4pxobserveduse

Motion

RoleCSS variableDefault valueStatus / eligibility
motion.duration.fast--motion-duration-fast80msobserveduse
motion.duration.base--motion-duration-base120msobserveduse
motion.duration.slow--motion-duration-slow150msobserveduse

Elevation

RoleCSS variableDefault valueStatus / eligibility
shadow.floating--shadow-floating0px 6px 22px 0px rgb(0 0 0 / 55%)observeduse

Layout

RoleCSS variableDefault valueStatus / eligibility
layout.measure--layout-measure72observeduse
layout.content-max--layout-content-max680pxobserveduse
layout.app-max--layout-app-max1440pxobserveduse

Breakpoints

RoleCSS variableDefault valueStatus / eligibility
breakpoint.xs--breakpoint-xs320pxobserveduse
breakpoint.sm--breakpoint-sm600pxobserveduse
breakpoint.md--breakpoint-md900pxobserveduse
breakpoint.lg--breakpoint-lg1280pxobserveduse

Icon sizes

RoleCSS variableDefault valueStatus / eligibility
icon.size.sm--icon-size-sm12pxobserveduse
icon.size.md--icon-size-md16pxobserveduse
icon.size.lg--icon-size-lg20pxobserveduse
icon.stroke--icon-stroke1.5pxobserveduse

Stacking

RoleCSS variableDefault valueStatus / eligibility
z.canvas--z-canvas0observeduse
z.raised--z-raised1observeduse
z.popover--z-popover10observeduse
z.drawer--z-drawer20observeduse
z.dialog--z-dialog30observeduse
z.toast--z-toast40observeduse

Actions

Buttons, links, icon buttons, button groups, segmented controls, destructive treatment.

Button button

  • Family: Actions
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <button type="button"> — APG pattern
  • specified
  • demonstrated
  • test implemented

The native push button in the four action tones; primary is the only filled button at rest, destructive fills on hover and always needs a confirmation or an undo.

Variants: Primary, Secondary, Tertiary, Destructive. States: default, hover, focus-visible, active, disabled, loading.

Icon button icon-button

  • Family: Actions
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <button> with aria-label; aria-pressed for the toggle — APG pattern
  • specified
  • demonstrated

A square ghost button whose only content is a 16px line icon; it always carries an accessible name and, as a toggle, aria-pressed.

Variants: Action, Toggle. States: default, hover, focus-visible, active, disabled, toggled, toggled+focus-visible.

Button group button-group

  • Family: Actions
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Native control: Labelled native button group
  • specified
  • demonstrated

Related independent native actions with individual tab stops.

Variants: Default. States: default, focus-visible, disabled.

Segmented control segmented-control

  • Family: Actions
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Native control: Native fieldset, legend and radio inputs
  • specified
  • demonstrated

A short exclusive choice implemented with labelled native radios.

Variants: Default. States: default, checked, focus-visible, disabled.

Basic forms

Text, password, number, search, textarea, select, checkbox, radio, switch, range, fieldsets, labels, help text, validation.

Field field

  • Family: Basic forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <label for> with aria-describedby on the control — APG pattern
  • specified
  • demonstrated

The label, control, help and message wrapper that every form control sits in; it fixes the stacking order, the required mark, the description links and the invalid message.

Variants: Default. States: default, required, invalid, disabled.

Text field text-field

  • Family: Basic forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <input> with <label> — APG pattern
  • specified
  • demonstrated
  • test implemented

Single-line free-text entry, covering every native input type that renders as a line box; search, number and password are variants, not separate components.

Variants: Text, Password with reveal, Search with clear, Number with stepper, With prefix and suffix. States: default, hover, focus-visible, placeholder-shown, filled, required, invalid, invalid+focus-visible, invalid+hover, disabled, disabled+filled, read-only, read-only+focus-visible, loading.

Textarea textarea

  • Family: Basic forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <textarea> with <label> — APG pattern
  • specified
  • demonstrated

Multi-line free-text entry in the same box as the text field; resizes vertically only and can show a character count.

Variants: Default, With character count. States: default, hover, focus-visible, placeholder-shown, filled, required, invalid, invalid+focus-visible, disabled, read-only.

Select select

  • Family: Basic forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Custom widget: Select-only combobox with listbox popup; multiple variant is a multiselectable listbox — APG pattern
  • specified
  • demonstrated
  • test implemented

A themed single-choice combobox or multiple-choice list backed by a native select for forms and the no-JavaScript fallback.

Variants: Single, With option groups, Multiple. States: default, hover, focus-visible, required, invalid, invalid+focus-visible, disabled.

Checkbox checkbox

  • Family: Basic forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <input type="checkbox"> with <label>; fieldset and legend for a group — APG pattern
  • specified
  • demonstrated
  • test implemented

The native checkbox drawn as a 16px square that fills with the primary action colour and a ✓ or – glyph; single, or a fieldset group of independent choices.

Variants: Single, Group. States: default, hover, focus-visible, checked, mixed, checked+focus-visible, checked+disabled, disabled, invalid, required.

Radio group radio-group

  • Family: Basic forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <input type="radio"> inside <fieldset> with <legend> — APG pattern
  • specified
  • demonstrated
  • test implemented

A fieldset of native radios for one exclusive choice; each radio is a 16px square that fills with the primary action colour and an inner square when checked.

Variants: Vertical, Horizontal. States: default, hover, focus-visible, checked, checked+focus-visible, disabled, invalid, required.

Switch switch

  • Family: Basic forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Custom widget: <button type="button" role="switch" aria-checked> — APG pattern
  • specified
  • demonstrated

An on/off control that takes effect immediately; a button with role switch and aria-checked, drawn as a square-cornered track with a square thumb that fills with the primary colour when on.

Variants: Default, With labels. States: default, hover, focus-visible, checked, checked+focus-visible, disabled, checked+disabled.

Fieldset fieldset

  • Family: Basic forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <fieldset> with <legend> — APG pattern
  • specified
  • demonstrated

The native fieldset that groups related fields under a legend inside a 1px divider border; disabling it disables everything inside.

Variants: Default. States: default, disabled.

Number field number-field

  • Family: Basic forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <input type="number"> with <label>; stepper buttons are separate <button>s — APG pattern
  • specified
  • demonstrated

The text-field box around a native number input with right-aligned tabular digits, an optional unit affix and two square stepper buttons that replace the host spinner.

Variants: Default, With unit. States: default, hover, focus-visible, invalid, invalid+focus-visible, disabled, read-only.

Search field search-field

  • Family: Basic forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <input type="search"> with <label> inside a role="search" landmark; status through role="status" — APG pattern
  • specified
  • demonstrated

The text-field box around a native search input with a magnifier, a clear button that appears with a value, an optional shortcut hint, a loading glyph and a no-results status line.

Variants: Default, With shortcut hint. States: default, hover, focus-visible, placeholder-shown, filled, loading, disabled, no-results.

Range range

  • Family: Basic forms
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Native control: Native labelled range input and output
  • specified
  • demonstrated

A bounded native numeric slider with visible output.

Variants: Default. States: default, focus-visible, disabled.

Advanced forms

Combobox, multiselect, date and time, file selection, repeaters, wizard, bounded form-builder specimen.

Combobox combobox

  • Family: Advanced forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Custom widget: APG combobox with list autocomplete: input role combobox owning a listbox of options — APG pattern
  • specified
  • demonstrated

A text input that filters a listbox of suggestions; the APG combobox with list autocomplete, rendered with the list open.

Variants: Flat list, Grouped options, No results. States: default, hover, focus-visible, open, closed, selected, invalid, invalid+focus-visible, disabled, no-results.

Date picker date-picker

  • Family: Advanced forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Custom widget: Labeled textbox with calendar dialog and roving date grid; native backing input — APG pattern
  • specified
  • demonstrated

A themed date editor and calendar, alone or as a from/to pair, backed by native form values and constraints.

Variants: Single date, From / to. States: default, hover, focus-visible, invalid, invalid+focus-visible, disabled, read-only.

Time picker time-picker

  • Family: Advanced forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Custom widget: Labeled textbox with native time constraints and named step buttons — APG pattern
  • specified
  • demonstrated

A themed time editor with explicit step buttons, backed by native time values and constraints.

Variants: Time. States: default, hover, focus-visible, invalid, invalid+focus-visible, disabled.

File input file-input

  • Family: Advanced forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <input type=file> named by two <label>s; the drop zone is a plain region, never a role — APG pattern
  • specified
  • demonstrated

A native file input behind a label styled as a secondary button, optionally inside a drop zone, with a list of chosen files and per-file errors.

Variants: Button, Drop zone, With chosen files. States: default, hover, focus-visible, drop-target, invalid, disabled, loading.

Wizard wizard

  • Family: Advanced forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <button>s in an <ol>; the current step carries aria-current=step; the panel is a section named by its heading — APG pattern
  • specified
  • demonstrated

A multi-step form with a stepper header, the current panel and back/next actions; native buttons with aria-current="step".

Variants: Numbered steps, Glyph markers. States: default, hover, focus-visible, current, disabled, invalid, busy.

Form builder form-builder

  • Family: Advanced forms
  • Maturity: draft
  • Priority: L
  • Since: 0.1.0
  • Native control: Native buttons, labelled inputs, fieldsets and ordered field definitions; no drag-only operations.
  • specified
  • demonstrated
  • test implemented
  • draft

A bounded reference editor for five canonical field kinds, with keyboard ordering, local preview and explicit JSON definition import and export.

Variants: Reference definition. States: default, empty, invalid, disabled.

Multiple selection multiselect

  • Family: Advanced forms
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Native control: Fieldset, legend, search input and native checkboxes
  • specified
  • demonstrated

A searchable native checkbox group that preserves all selected form values.

Variants: Default. States: default, checked, focus-visible, disabled, no-results.

Repeater repeater

  • Family: Advanced forms
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Native control: Ordered list, inert template and native controls
  • specified
  • demonstrated

Repeat native field rows with stable identities and keyboard ordering.

Variants: Default. States: default, empty, focus-visible, disabled.

Navigation

Tabs, breadcrumbs, pagination, sidebar, toolbar, menus, command palette, tree.

Tabs tabs

  • Family: Navigation
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Custom widget: APG tabs (tablist, tab, tabpanel) with roving tabindex — APG pattern
  • specified
  • demonstrated
  • test implemented

A tablist of buttons that switches between panels in place; the selected tab carries a 2px indicator bar and bright text, never a fill.

Variants: Default, Overflow. States: default, hover, focus-visible, selected, selected+focus-visible, selected+container-inactive, disabled.

Breadcrumbs breadcrumbs

  • Family: Navigation
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native nav > ol with aria-current="page" on the last item — APG pattern
  • specified
  • demonstrated

The path from the root to the current page as an ordered list of links separated by slashes; the last item is the current page and not a link.

Variants: Default, Truncated. States: default, hover, focus-visible, current, truncated.

Pagination pagination

  • Family: Navigation
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native nav > ul of links with aria-current="page"
  • specified
  • demonstrated

Page links for a long result set; the current page takes the selection fill and aria-current, and the compact form reads "3 of 12" between previous and next.

Variants: Default, Compact. States: default, hover, focus-visible, current, disabled.

Sidebar navigation sidebar-nav

  • Family: Navigation
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native nav with nested ul lists; groups are buttons with aria-expanded — APG pattern
  • specified
  • demonstrated

A vertical list of section links with optional nested groups; the current section carries a 2px inline-start indicator and bright text, and the rail collapses to icons.

Variants: Default, Collapsed, Nested. States: default, hover, focus-visible, current, selected, selected+container-inactive, expanded, collapsed.

Toolbar toolbar

  • Family: Navigation
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Custom widget: APG toolbar with roving tabindex; buttons, toggle buttons with aria-pressed, and a separator — APG pattern
  • specified
  • demonstrated

A row of related controls under one tab stop with arrow-key movement; ghost buttons, a vertical separator, and a "more" button when the row overflows.

Variants: Default, Overflow. States: default, hover, focus-visible, disabled, toggled.

Menu menu

  • Family: Navigation
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Custom widget: APG menu button (button with aria-haspopup="menu") opening a menu of menuitem, menuitemcheckbox and separator — APG pattern
  • specified
  • demonstrated
  • test implemented

A menu button that opens a list of actions on the raised surface inside a 1px overlay border; the active item is the selection fill and check items show a glyph.

Variants: Default, With submenu, With checks. States: default, hover, focus-visible, open, closed, disabled, checked, selected.

Command palette command-palette

  • Family: Navigation
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Custom widget: combobox — APG pattern
  • specified
  • demonstrated

A compact square modal command prompt with local results and category labels.

Variants: Default. States: default, open, closed, focus-visible, no-results.

Tree tree

  • Family: Navigation
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Custom widget: treeview — APG pattern
  • specified
  • demonstrated

Hierarchical navigation with explicit expansion and one roving tab stop.

Variants: Default. States: default, selected, expanded, collapsed, focus-visible, disabled.

Disclosure disclosure

  • Family: Navigation
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Native control: Native details and summary
  • specified
  • demonstrated

Native details and summary for supporting content.

Variants: Default. States: default, expanded, collapsed, focus-visible.

Information display

Cards, lists, badges, chips, avatars, descriptions, tables, timelines, simple charts.

Card card

  • Family: Information display
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native article or section; link cards are a single anchor; selectable cards are options inside a listbox — APG pattern
  • specified
  • demonstrated

A bordered panel that groups a title, body and metadata; a link card makes the whole panel one link, a selectable card is an option with the selection fill.

Variants: Default, Link card, Selectable. States: default, hover, focus-visible, selected, selected+focus-visible.

List list

  • Family: Information display
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Custom widget: APG listbox with roving tabindex; options carry aria-selected, the list aria-multiselectable when several may be chosen — APG pattern
  • specified
  • demonstrated

A selectable list of rows (an APG listbox) in single or multiple selection; the selected row is the selection fill with a check glyph and an optional metadata column.

Variants: Single, Multi, With metadata. States: default, hover, focus-visible, selected, selected+focus-visible, selected+container-inactive, disabled.

Badge badge

  • Family: Information display
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native span; an empty badge is role="img" with aria-label
  • specified
  • demonstrated

A small square label for a status or a count; every status carries its glyph and its fill, the outline form uses the status border, and an empty badge is a dot with a name.

Variants: Status, Count, Outline. States: default, empty.

Chip chip

  • Family: Information display
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native button with aria-pressed for filters; a span with a labelled remove button for values; a plain span for tags
  • specified
  • demonstrated

A square bordered token for a filter, a removable value or a static tag; a pressed filter chip takes the selection fill and a check glyph.

Variants: Filter, Removable, Static. States: default, hover, focus-visible, selected, selected+focus-visible, disabled.

Table table

  • Family: Information display
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native table with caption, thead, th scope, aria-sort on sorted headers and aria-busy while loading
  • specified
  • demonstrated
  • test implemented

A native data table with a header rule, row dividers, hover and selection fills, sortable headers with a glyph, and static empty and loading rows.

Variants: Default, Sticky header, Numeric, With caption. States: default, hover, selected, selected+focus-visible, selected+container-inactive, sorted, empty, loading.

Data table data-table

  • Family: Information display
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native table with aria-selected rows, a select-all checkbox in the mixed state, aria-sort headers and aria-busy while loading — APG pattern
  • specified
  • demonstrated

A native table with controls: a selection column with a mixed select-all, sortable headers, row focus with the ring on the fill, and static resize handles.

Variants: Default, Selectable, Resizable. States: default, hover, focus-visible, selected, selected+focus-visible, sorted, mixed, empty, loading.

Description list description-list

  • Family: Information display
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Native control: Native dl, dt and dd
  • specified
  • demonstrated

Semantic terms and values that wrap into a readable single column.

Variants: Default. States: default, stacked.

Avatar avatar

  • Family: Information display
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Native control: Named image or text fallback
  • specified
  • demonstrated

A square entity image with a named text fallback.

Variants: Default. States: default, loading, error.

Timeline timeline

  • Family: Information display
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Native control: Ordered list with time elements
  • specified
  • demonstrated

Chronological events with explicit dates, descriptions and current state.

Variants: Default. States: default, current.

Chart chart

  • Family: Information display
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Native control: Native figure, accessible SVG and table
  • specified
  • demonstrated

A one-series numeric chart with an always-visible complete data table.

Variants: Default. States: default, empty, loading.

Keyboard key kbd

  • Family: Information display
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Native control: Native kbd
  • specified
  • demonstrated

A literal key or short keyboard sequence rendered as native kbd text.

Variants: Default. States: default.

Feedback and overlays

Alerts, toasts, progress, loading, skeletons, tooltips, popovers, dialogs, drawers, empty and error states.

Alert alert

  • Family: Feedback and overlays
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native landmark-free block; role=alert for danger, role=status for every other status; an optional native close button — APG pattern
  • specified
  • demonstrated

An inline status message with a mandatory glyph on the status tint behind a 1px status border; role alert for danger, status otherwise.

Variants: Danger, Warning, Success, Info, Neutral, Dismissible. States: default, hover, focus-visible.

Toast toast

  • Family: Feedback and overlays
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <div role=status> (role=alert for danger) inside a region named Notifications; native buttons for the action and dismiss — APG pattern
  • specified
  • demonstrated

A brief notification in a fixed corner stack; canvas surface behind a 1px overlay border, status tints for the four polite statuses and the danger fill for critical ones.

Variants: Plain, Five statuses stacked, With action. States: default, hover, focus-visible, stacked, reduced-motion.

Progress progress

  • Family: Feedback and overlays
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <progress> labelled by <label for>; aria-valuetext for indeterminate work — APG pattern
  • specified
  • demonstrated

A native progress element with a label and value; determinate fills with the primary colour, indeterminate shows static 45° stripes, never an animation.

Variants: Determinate, Indeterminate, With detail line. States: default, busy, error, reduced-motion.

Loading indicator loading-indicator

  • Family: Feedback and overlays
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native container with aria-busy=true and role=status; the glyph is aria-hidden and the label carries the meaning — APG pattern
  • specified
  • demonstrated

A static ⋯ glyph with a worded label inside an aria-busy container; inline next to text or as a centred block. There is no spinner.

Variants: Inline, Block. States: default, reduced-motion.

Tooltip tooltip

  • Family: Feedback and overlays
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Custom widget: APG tooltip: a trigger with aria-describedby pointing at an element with role=tooltip, shown on hover and focus, hidden on Escape — APG pattern
  • specified
  • demonstrated

A short description of a control shown on hover and focus; role tooltip linked by aria-describedby, a 1px overlay border on the raised surface, no arrow.

Variants: Description, With shortcut. States: default, hover, focus-visible, open, closed.

Dialog dialog

  • Family: Feedback and overlays
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <dialog> opened with showModal; role=alertdialog for confirmations; named by its heading, described by its first paragraph — APG pattern
  • specified
  • demonstrated
  • test implemented

A native dialog on the overlay surface behind a 1px overlay border and the backdrop; modal when shown, with trapped focus and Escape to close.

Variants: Confirm, Alert dialog, Form. States: default, open, closed, focus-trapped, hover, focus-visible, reduced-motion.

Drawer drawer

  • Family: Feedback and overlays
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <dialog> opened with showModal, anchored to an inline edge; named by its heading; Escape closes — APG pattern
  • specified
  • demonstrated

A full-height modal panel anchored to the start or end edge; a native dialog on the overlay surface with a 1px overlay border on its inner edge.

Variants: Start edge, End edge. States: default, open, closed, focus-trapped, reduced-motion.

Empty state empty-state

  • Family: Feedback and overlays
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native block; a heading and a paragraph inside the region the content would fill; the action is a native <button> or <a> — APG pattern
  • specified
  • demonstrated

What a container shows when it has nothing to list; a glyph, a heading in the bright text colour, one sentence in the muted colour and an optional secondary action.

Variants: With action, Without action. States: default.

Skeleton skeleton

  • Family: Feedback and overlays
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Native control: Native status text with aria-hidden decorative blocks
  • specified
  • demonstrated

Static layout placeholders with a named loading status.

Variants: Default. States: default, loading, reduced-motion.

Popover popover

  • Family: Feedback and overlays
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Native control: Native button and named supporting section
  • specified
  • demonstrated

A non-modal supporting panel with light dismissal and ordinary tab order.

Variants: Default. States: default, open, closed, focus-visible.

Error state error-state

  • Family: Feedback and overlays
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Native control: Named section and native retry button
  • specified
  • demonstrated

A specific failure explanation with an explicit recovery request.

Variants: Default. States: default, error, loading, disabled, focus-visible.

Developer interfaces

Editor syntax, gutters, caret, selections, search, diagnostics, diffs, terminal text and the historical ANSI slots.

Code editor code-editor

  • Family: Developer interfaces
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Custom widget: presentation of <pre> inside role=textbox with aria-multiline and aria-readonly; a real editor is a host surface — APG pattern
  • specified
  • demonstrated
  • test implemented

The editor surface, gutter, caret, current line, selection, bracket match and monochrome syntax roles that every code-editing or code-viewing host maps onto.

Variants: JavaScript, Markup, Folded region. States: default, focus-visible, selected, selected+container-inactive, current, read-only.

Diagnostics diagnostics

  • Family: Developer interfaces
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Custom widget: inline: decorated spans inside a read-only textbox presentation; panel: APG listbox with aria-activedescendant — APG pattern
  • specified
  • demonstrated

Inline problem markers in code (underline patterns, an error line and an overview stripe) and the problems panel that lists them as a listbox, each severity carrying its glyph.

Variants: Inline markers, Problems panel. States: default, hover, focus-visible, selected, selected+focus-visible, error, empty.

Diff view diff-view

  • Family: Developer interfaces
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <table> with a caption; one row per line; collapsed hunks are a <button> with aria-expanded controlling a hidden <tbody> — APG pattern
  • specified
  • demonstrated

Unified and split diffs as native tables; added, removed and modified rows keep their textual gutter marker, word-level changes are underlines, conflicts are double borders.

Variants: Unified, Split, Word-level, Merge conflict. States: default, hover, selected, focus-visible, expanded, collapsed.

Terminal terminal

  • Family: Developer interfaces
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <pre role=log> for a transcript; a plain <pre> with aria-label for the slot grid and the attribute sheet — APG pattern
  • specified
  • demonstrated

Terminal text with the readable heritage sixteen ANSI slots (D-029, D-032), the cursor, the selection and the six text attributes; a transcript, the slot grid and the attributes.

Variants: Transcript, ANSI grid, Attributes. States: default, focus-visible, selected, busy, current.

Composed specimens

Settings panel, administrative form, filterable table, i3-inspired window frame; file browser, compact dashboard and form builder later.

Settings panel settings-panel

  • Family: Composed specimens
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: region landmark named by the h2; a nav landmark for the sections with aria-current on the open one; a form landmark holding native controls in one fieldset; aria-busy on the form while applying — APG pattern
  • specified
  • demonstrated

A two-column settings screen composed from the sidebar-nav, fieldset, switch, select, radio-group, text-field, checkbox and button components; below 600px the sidebar becomes a tab strip.

Variants: Two columns, Narrow (360px). States: default, focus-visible, invalid, busy.

Admin form admin-form

  • Family: Composed specimens
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: region landmark named by the h2; a Breadcrumb nav landmark; the wizard step list with aria-current=step; role=status and role=alert notices; a form landmark of native controls; aria-busy on the form while saving; a disabled fieldset around it while inert — APG pattern
  • specified
  • demonstrated
  • test implemented

A create-or-edit record screen composed from breadcrumbs, a wizard step list, alerts, six field components and a button row; the review step is a table with an Edit button per row.

Variants: Identity step, Review step. States: default, invalid, busy, disabled.

Filterable table filterable-table

  • Family: Composed specimens
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: region landmark; a toolbar with roving tabindex holding a search landmark, a menu button, a toggle icon button and a button; a group of removable chips; a grid-less native table with aria-sort, aria-selected rows and a checkbox-role select-all; role=status for the count; a pagination nav — APG pattern
  • specified
  • demonstrated

A list screen composed from a toolbar with search and filter, removable chips, a selectable sortable data-table with status badges, a count and pagination; with empty and loading variants.

Variants: Eight of 43, Nothing matches, Loading. States: default, hover, focus-visible, selected, no-results.

i3 window frame i3-window-frame

  • Family: Composed specimens
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: region landmark; a group for the bar holding a tablist of workspaces (aria-selected on the visible one) and a labelled status group; each window a focusable named group, or a tablist and tabpanels in the tabbed variant; the clients keep their own roles (log, textbox) — APG pattern
  • specified
  • demonstrated

The workstation frame; an i3 bar with workspaces and Chinese i3status labels above the terminal and code-editor components as tiled, tabbed or floating windows behind i3 title bars.

Variants: Tiled, Tabbed, Floating. States: default, focus-visible, selected, container-inactive, error.

File browser file-browser

  • Family: Composed specimens
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Native control: Tree composition, native search input and table
  • specified
  • demonstrated

Location navigation and a filterable native file table with bounded host actions.

Variants: Default. States: default, selected, empty, no-results, focus-visible.

Compact dashboard compact-dashboard

  • Family: Composed specimens
  • Maturity: stable
  • Priority: R2
  • Since: 1.0.0
  • Native control: Native sections, description lists, chart and table composition
  • specified
  • demonstrated

Named operational metrics, a complete chart and an actionable native records table.

Variants: Default. States: default, loading, empty, focus-visible.

Stress fixtures and non-examples

Stress fixtures and labelled non-examples →

s-stress

s-non-examples

fx-fx-long

fx-fx-320

fx-fx-i18n

fx-fx-rtl

fx-fx-rm

fx-fx-hc

fx-fx-touch

fx-fx-density

fx-fx-overflow

x-pills

x-glass

x-gradients

x-glow

x-everything-red

x-material

x-light

x-rainbow

x-traffic-light

x-sans

x-inactive-text

x-focus-as-selection

x-heritage-ui

x-circles

x-hairline-edge

x-opacity-disabled

Form composition and recovery

A local reference workflow preserves values through validation, review and an explicitly simulated save.

Scope

The validation and recovery pattern composes admin-form, text-field, textarea, select, checkbox, alert, button and table under proposed D-020. It is a reference composition, not an approved profile or a persistence system; the component rules still apply. Its JSON contract (spec/patterns/validation-recovery.json) records the components’ content digests, fields, fixtures, transitions and limits.

Interaction

  1. Submit to validate. Errors appear together in a focused summary linking to the affected fields; every entered value is kept, including unrelated notes and choices.
  2. Correct and submit again to reach review. Editing never announces errors per keystroke nor silently removes the last submitted summary. Review offers an explicit way back to editing.
  3. Confirming the review enters busy: controls are disabled and a pending message is shown.
  4. Only the separate Complete simulation action reaches success; a submit click alone never does.

Busy, disabled, invalid and success each mean something different. Reset clears in-memory values and errors.

The ws-07 conflict on Name and Hostname and the lowercase hostname rule (letters, digits, hyphen-separated segments) are local admin-form fixtures, not server checks; no request, account, storage or database is involved. Without JavaScript the page keeps static normal, invalid, busy and success examples.

Evidence and limits

Automated protocols cover keyboard submission, summary navigation, correction, preservation, review, busy, success, narrow layout and no-JS content; a test that exists is not a passing run (see the verification report). No manual screen-reader pass is claimed. Submit-time feedback follows the GOV.UK validation pattern.

Figma Variables bridge

A one-way, pinned Variables API bridge with explicit diffs and external ownership receipts.

Supported mapping

This independently written bridge maps sRGB colors to COLOR variables and scalar px spacing and radius to FLOAT variables.

  • Aliases stay native variable aliases.
  • Token paths are stable identities. Slash-separated names live in the j3w1/theme/default/v1 collection.
  • Alias primitives are dependencies with empty property scopes, not newly approved application roles.
  • Semantic scopes are specific to text, fills, strokes, gaps and corner radius.
  • Eligibility and pending decision IDs travel with each definition.

Only the approved default profile is imported; heritage and proposed profiles are reported, never turned into extra modes. Typography, shadows, composite borders and other unsupported types are reported, not flattened. Figma does not import this JSON natively; the adapter uses the Variables Plugin API. Fonts are neither imported nor distributed: install the families the pinned typography tokens name.

Generate a pinned payload

In a verified checkout, run:

node scripts/figma-bridge.mjs --ref FULL_COMMIT_OR_RELEASE_TAG > payload.json

The default sample is color.surface.default, color.text.default, space.4 and radius.none, plus their two alias dependencies; --roles takes an explicit comma-separated list instead. The command reads Git objects at the resolved full revision, never moving branch bytes or the working tree, and records source and payload digests, the mapping version, unsupported items and excluded profiles.

Reviewed import route

Use the Figma connector’s use_figma Variables API route, in a new design draft or an existing collection whose current receipt you hold, after reading the connector’s current skill/API instructions. The adapter is exports/figma/importer.mjs; pin its download to the same reviewed delivery revision as these instructions.

  1. Load the module’s function in the connector script (remove only the ES-module export keyword), then return the awaited call:

    return await importFigmaVariables(figma, {
      payload, receipt: null, documentKey, action: "dry-run"
    });
  2. Pass the locally generated payload and the exact target file key as explicit inputs.

  3. Inspect the returned diff. Dry-run only reads.

  4. Call again with action: "apply", only for the reviewed change.

  5. Keep the whole returned receipt outside the document and the repository. Every later dry-run and apply must pass that receipt and the same document key.

An exact re-import changes nothing; updates show before/after definitions. Owned variables left out of a payload are kept and reported, never silently removed. Receipts are trusted local ownership records, not importable third-party configuration.

Limits of this route:

  • at most eight variables, dependencies included, per namespace; one collection; one default mode — small enough for one incremental connector operation. Larger payloads fail before anything changes;
  • apply and rollback need the connector’s atomic script execution; this module is not a standalone plugin transaction manager;
  • no team publishing permission or paid plan capability is assumed;
  • permission, mode and API errors stay failures.

Rollback and conflicts

To undo the most recent apply, call with action: "rollback" and the current receipt.

  • Existing variables get back their exact recorded values and metadata.
  • New variables are removed in reverse dependency order.
  • The result returns the previous receipt. Keep it for another rollback or a later import.
  • A newly created collection is removed only when it holds no unrelated variables.
  • Rollback refuses to remove a variable that a kept variable in any local collection still references. Check any canvas bindings you added after the import before you roll back; this adapter does not audit every canvas node.

Before any change, the adapter compares every owned ID, value, description, scope, collection identity and mode against the receipt; missing, detached or hand-edited variables stop apply and rollback. It never adopts a matching name without a receipt. Resolve a conflict deliberately in Figma or in a separate draft; never discard ownership records to force an overwrite.

Actual verification status

A real six-variable sample was imported through the connector into a new design draft, with Starter/Full access and Plugin API 1.0.0.

  • Alias IDs matched. Spacing and radius matched exactly.
  • Color channels matched the exact float32 form of the source channels, with no tolerance.
  • An exact re-import changed no IDs.
  • A separately previewed spacing addition was applied and rolled back.
  • A deliberate manual edit was rejected without being overwritten; the test edit was then explicitly restored.

Private receipts stay outside public artifacts; the issue evidence records the exact candidate and source revision. Source protocols also cover detached IDs, value updates, first rollback, unrelated variables, invalid payloads and extra modes against an explicit API fixture; these are fixture results, not account-capability claims. No component kit, native port, library publication, manual design review or automatic Figma-to-token sync is claimed. D-019 remains proposed.

Accessibility

Contrast targets, focus and keyboard contracts, reduced motion, forced colours, and what an automated pass does and does not prove.

What is claimed

WCAG 2.2 criteria are measurable design targets for the theme’s roles. A green contrast report and a clean automated scan show that the specified colours and the reference markup meet them; they are not a conformance claim for any adopting application. Keyboard operation, focus management, labels, reflow and manual review stay the consumer’s job. The theme’s own limits are under Limitations.

Contrast

  • Ordinary text: at least 4.5:1 against the actual background of its state, measured on resolved sRGB values after compositing translucent colours.
  • Large text (18.66px bold or 24px regular and above): at least 3:1.
  • Control boundaries, focus rings, meaningful icons and chart marks: at least 3:1 (WCAG 1.4.11).
  • Disabled text is exempt under WCAG 1.4.3; house policy still needs 3:1 (text.disabled), below the ordinary-text floor by design.
  • Never round a value into a pass. The report keeps the unrounded ratio and shows two decimals: 4.4996 reads 4.50 and fails.
  • Heritage values that fail (#a3676b as text, #7d1310 anywhere as text) are flagged $deprecated in the heritage-ansi profile, never shown as ordinary passes.

exports/contrast.md lists every declared pair (the global pairs in spec/contrast.json and every component’s stateTokens and contrast[] entries) with its computed ratio. Waived pairs carry their reason; a waiver is valid only for decorative graphics that are never the only boundary of a control.

Text hierarchy

The colour roles are in spec/foundations.md, Typography semantics (D-033); D-041 uses rose application text and terminal/agent prose; white is limited to document headings, exceptional highlights and contrast-critical roles. Bold inherits its context. Selection and contrast-critical on-fill roles are checked against their actual backgrounds. Heading level is conveyed through structure, size and weight, never colour alone.

Focus

Focus is never lost and never invisible. The ring is defined once, in spec/foundations.md, Interaction states, rule 2 (D-006, D-015).

  • :focus without :focus-visible draws nothing: pointer clicks stay quiet, keyboard focus stays visible.
  • The state matrices render every declared combination, including selected+focus-visible and invalid+focus-visible, where rings disappear in practice.

Keyboard

Native controls keep native keyboard behaviour. Custom widgets follow the WAI-ARIA Authoring Practices pattern in their aria.apg:

  • roving tabindex in toolbars, tabs, trees and listboxes;
  • aria-activedescendant in comboboxes;
  • focus trapping and Escape in dialogs and drawers;
  • arrow keys in radio groups and menus.

Positive tabindex is banned. Every icon-only control has an accessible name. The site’s own controls (search, filters, inspector, copy) work with the keyboard, and the no-JS build keeps every normative section readable.

Motion

Motion follows spec/foundations.md, Interaction states, rule 7. Under prefers-reduced-motion: reduce:

  • toasts, dialogs and drawers appear in place;
  • indeterminate progress shows static stripes;
  • loading glyphs do not spin;
  • skeletons do not shimmer;
  • tab indicators do not slide.

Forced colours and high contrast

Under forced-colors: active, rings use Highlight and selections Highlight / HighlightText. Borders survive because they are real borders, not box-shadows; pattern fills keep charts and diffs readable.

Reflow, zoom and text

Components reflow at 320 CSS pixels without horizontal page scrolling, at 200% browser zoom and at 200% text-only zoom. Rings and borders stay 1px / 2px CSS. Targets are at least 24×24 CSS pixels, with 4px spacing in compact density. Long labels wrap, or truncate with a visible affordance; the stress fixtures (English, Spanish, Chinese, Arabic with dir="rtl") exercise this.

Colour is never the only channel

Every status has a glyph; every state a border, pattern or ARIA change. Diffs keep their + − ~ markers. Charts carry pattern fills and a table fallback. The heritage-ansi terminal palette has less hue difference by design, a recorded limit.

Limitations (recorded, not hidden)

  • The theme specifies colours, states and reference markup. It cannot make a host application’s own focus management, labels or reading order correct.
  • The automated scan uses axe-core with the WCAG 2.x A and AA rule sets and does not test every success criterion. Manual checks (keyboard walks, screen-reader reading, zoom) need their own execution evidence; a missing protocol stays not run.
  • The default semantic terminal palette targets 4.5:1 for slots 1–15 on true-black terminal.bg (D-041); ANSI 0 is the background. In heritage-ansi, slots 1, 4, 6, 8, 9, 10, 12, 13, 14 and 15 fail 4.5:1. Host dimming, non-default backgrounds and explicit true-colour output need their own measurements.
  • Editors and diff viewers may preserve syntax foregrounds over selection or change fills. Check those actual pairs, not only syntax on the canvas. Claude Code reuses word-highlight backgrounds as edit-summary foregrounds; its port documents the resulting limitation separately from normal diff line contrast.
  • interaction.text-selection.tint (D-036) requires the host’s compositing behavior to be known. A tint under text and the same tint painted over text have different contrast. The global pairs composite it over the canvas; Telegram’s tests cover its raised and accent surfaces. Those measurements do not certify every host, selected link or syntax span. The earlier rose-palette selection measurements are historical after D-041 and cannot be carried forward as current results.

Verification evidence and freshness

Source coverage. The coverage ledger records source facts: specified, demonstrated and test implemented. exports/coverage.json schemaVersion 1 adds testImplemented and keeps tested as a compatibility alias meaning the test file exists; component JSON and family totals use the same definitions. No coverage Boolean proves an execution or WCAG conformance.

Execution evidence. The static verification report gives per-test outcomes and per-component summaries. Evidence schemaVersion 1 records, for each result:

  • the method (automated or manual), category and component;
  • the states and variants it explicitly covers (empty lists mean “unspecified”, never “all”);
  • browser and version, OS, viewport, profile, density and JavaScript setting;
  • a run or protocol reference.

The recorded profile and density are the page’s declared data-profile and data-density when the test ends; tests that switch them say so in their scope. One browser engine never stands for another. Skipped, failed, not run and not applicable are separate outcomes, and every non-pass has a reason. Manual screen-reader and keyboard claims need protocol records. The automated suite targets Chromium; other engines stay not run.

Freshness. A claim is current only while the tested artifact’s digest and a broad source fingerprint both match. The fingerprint covers tracked contract sources, schemas, generators, site code, tests, agent guidance, CI configuration and the package lockfile, so an unrelated change can stale more evidence than strictly needed. A stale record keeps its real outcome and reference but no longer shows a current pass.

How the report is built.

  1. A build first publishes a static not-run report and a subject manifest.
  2. The browser reporter checks that source and specimen assets still match that subject before it publishes execution evidence.
  3. Report generation writes only under dist/verification/ and checks that every specimen byte is unchanged.
  4. The report’s own presentation has a separate static and browser gate; it never certifies itself.

Run timestamps and revisions live only in this post-test evidence, outside the committed exports and their digests, so no hash depends on itself.

Run it locally.

  1. Build the site.
  2. Run the browser suite.
  3. Run npm run verification:report, then npm run verification:check, then npm run test:verification.

A local run names its local execution and digests and is never presented as hosted CI evidence.

Record a manual protocol. Pass a schema-valid evidence document to node scripts/verification-report.mjs <repo-relative-evidence.json>, carrying the real tested digests, the browser and environment, and a protocol: reference with the protocol identifier and recorded observations. Keep the protocol with the evidence; never copy private artifacts into this public repository.

Contrast report

993 declared pairs measured on resolved sRGB values with the WCAG 2.x formula; 7 waived (decorative only), 0 failing. A pass is a design target for the named role, not an application-wide conformance claim.

Every pair, computed ratio and waiver →

Portability

How the theme travels to other applications and frameworks, what a port must reproduce, what it may declare unsupported, and how support is catalogued truthfully.

Scope of a port

A port themes only what the host documents as customisable. Editor colours, application chrome, terminal colours and plugin surfaces are separate scopes; a file that changes one does not claim the others. A port never:

  • patches binaries or injects unsupported hacks (D-034 permits only the pinned, compatibility-checked Windows Windhawk styling adapter);
  • overwrites a user’s whole settings file;
  • replaces keybindings, credentials or unrelated preferences.

It installs under a unique name beside the host’s defaults and documents the rollback.

What every port must reproduce

  1. The surface ladder: canvas, default, raised, overlay, input.
  2. The text ladder: rose default, bright, prose, muted, subtle and disabled; white document headings and exceptional highlights; bold inherits color. Ordinary UI labels remain rose.
  3. Focus as a ring distinct from selection as a fill, with the ring recoloured on fills.
  4. Selection, inactive selection and hover as three distinguishable fills.
  5. The status hues with their glyphs where the host renders glyphs.
  6. Zero radii and 1px borders where the host allows geometry; otherwise a recorded deviation.
  7. The monospace family by name, honouring the user’s size.

Every required role is mapped, explicitly inherited from the host, marked unsupported with a reason, or intentionally out of scope. A coverage percentage means something only with its denominator.

Fallbacks by host capability

Host capabilityFallback
No dashed outlines (many native toolkits)solid 1px ring in focus.ring; record the deviation
No separate inactive selectionselection fill everywhere; record it
No read-only styling hooktreat as default text with a dotted bottom edge if borders are available, else as default
No pattern fills (charts)keep the glyph or label channel; never colour alone
Sixteen-colour terminaldefault (the semantic sixteen, D-041); heritage-ansi only for historical fidelity; extended remains proposed; document bold-as-bright and whether 256/24-bit colours bypass the slots
Fixed radii in the hostdocument; do not fight the toolkit
Host forbids removing its focus indicatorkeep the host’s indicator; never draw two

Shared component defaults

Components whose Portability section links here follow these rules; their responsive and portability.nativeFallbacks fields carry them into the exports.

  • Wrap labels and actions without changing source order.
  • Use logical spacing in RTL.
  • Preserve native target sizes at both densities; only bounded data regions may scroll horizontally.
  • Use equivalent native semantics and approved roles; record any unsupported behavior as a mapping deviation.
  • The host owns application data, persistence, permissions and services.

Web consumers

exports/tokens.css exposes every role as a custom property. Consume roles (--color-text-default), never primitives. A framework integration maps roles onto the framework’s theme keys and lists what it cannot express. agents/consume.md gives the reading order and the deviation report format; theme.lock.json pins the revision.

Native ports

A port lives at ports/<slug>/ with a README, port.json, mapping.json and importable artifacts under dist/. Add src/ only for real generator inputs that these sources cannot express, and evidence/ only for actual evidence; neither needs a placeholder directory. templates/port/ is a starting aid when work begins.

  • capabilities.json refines each role into mapped, inherited, unsupported, out-of-scope or not-implemented, with a surface and a reason (D-018). A legacy unmapped reason stays unclassified, never guessed. One generated catalogue feeds the summaries, drill-downs and task kits; private parity records never enter it.
  • Every port classifies a new role, even when only one maps it. Telegram alone maps surface.accent (outgoing bubbles; incoming stay surface.raised, timestamps on both text.muted) and interaction.text-selection.tint (Android text selection; Desktop keeps selection.bg with near-white text). Claude Code’s userMessageBackground keeps interaction.selection.bg, and Obsidian, which keeps the text colour, would suit the tint; each adoption is a separate change with its own import check (D-035, D-036).
  • Statuses are experimental, verified and deprecated. Reference implementations and roadmap candidates are not statuses.
  • verified needs a real import into the recorded application version, with matching evidence and a token digest equal to the current default profile. Import verification is separate from mapping state and declared status: a relevant change to the target, tokens, mappings, capabilities or artifact bytes makes evidence stale, and a failed or missing check never passes. A successful XML or JSON parse is a structural pass, not verification.
  • Never hand-edit a generated hex. Fix the mapping or the approved token and regenerate.
  • npm run generate writes dist/ for every port whose format has an emitter in scripts/lib/port-artifacts.mjs (warp-yaml, ghostty-config, claude-theme-json, codex-tmtheme, chatgpt-appearance, orca-theme, obsidian-theme, windows-theme and telegram-theme today). Each emitter returns the complete declared array of text or byte artifacts. Binary files are hashed and copied byte for byte; text files retain the existing line-ending convention. Unsafe or duplicate paths and missing/extra outputs fail before any port artifact is written. Obsidian emits a manifest and CSS together; Telegram emits Android text and a Desktop zip. Orca emits its app/editor and terminal data-theme plugin alongside the compatible Ghostty export; the Ghostty file alone does not configure full application appearance.
  • The README downloads table links each file at the release tag; the site serves a copy at ports/<slug>/<file>.

For JetBrains, an editor scheme (.icls) and a UI theme plugin are separate capabilities; the scheme alone does not recolour toolbars or dialogs. For Notepad++, a style-theme XML, the dark-mode chrome setting and User Defined Languages are three separate mechanisms. Read the vendor documentation for the tested version before mapping.

The reference implementation

j3w1/j3w1.github.io is the flagship web implementation and the source of the observed values. Nothing is scraped at build time or synchronised in either direction. An integration there pins a release of this theme through a separate reviewed change and records its site-specific values (window-manager geometry, wallpaper gradients) as such.

Application ports

Explore capabilities and semantic mappings

PortFormatStatusThemeTested onSupported / inherited / unsupported
ChatGPT desktop app (Appearance)chatgpt-appearanceDeclared experimental; evidence: not verified4.0.0— (windows, macos)1 / 0 / 9
Claude Code (custom theme)claude-theme-jsonDeclared experimental; evidence: not verified4.0.0— (linux, macos, windows)1 / 1 / 2
Codex CLI (tmTheme)codex-tmthemeDeclared experimental; evidence: not verified4.0.0— (linux, macos, windows)1 / 1 / 3
Ghostty themeghostty-configDeclared experimental; evidence: not verified4.0.0— (macos, linux)3 / 1 / 1
Obsidian themeobsidian-themeDeclared experimental; evidence: not verified4.0.0— (any)3 / 1 / 2
Orca (app, editor and terminal)orca-themeDeclared experimental; evidence: not verified4.0.0— (windows, macos, linux)7 / 2 / 3
Telegram Android and Desktoptelegram-themeDeclared experimental; evidence: stale4.0.0Telegram Android 12.10.6, Telegram Desktop 7.2.9 (android, windows, linux, macos)4 / 3 / 1
Warp theme YAML (also Orca's Import from YAML)warp-yamlDeclared experimental; evidence: not verified4.0.0— (windows, macos, linux)1 / 1 / 3
Windows 11 native and Windhawk themewindows-themeDeclared experimental; evidence: not verified4.0.0— (windows)4 / 1 / 1

Coverage ledger

Specified: spec/components/<id>.md validates. Demonstrated: <id>.demo.html exists with a fragment for every declared variant and renders on the site. Test implemented: tests/browser/components/<id>.spec.js exists; does not establish a pass. Computed from the sources, never declared.

Execution results are separate: verification summaries and full matrix. Missing browser or manual evidence is not run.

FamilyTotalSpecifiedDemonstratedTest implemented
composed6661
feedback1111111
display1111111
navigation1010102
actions5552
forms-basic1111114
developer5551
forms-advanced8881
ComponentFamilyPrioritySpecifiedDemonstratedTest implemented
admin-form · evidencecomposedR1yesyesyes
alert · evidencefeedbackR1yesyes—
avatar · evidencedisplayR2yesyes—
badge · evidencedisplayR1yesyes—
breadcrumbs · evidencenavigationR1yesyes—
button-group · evidenceactionsR2yesyes—
button · evidenceactionsR1yesyesyes
card · evidencedisplayR1yesyes—
chart · evidencedisplayR2yesyes—
checkbox · evidenceforms-basicR1yesyesyes
chip · evidencedisplayR1yesyes—
code-editor · evidencedeveloperR1yesyesyes
combobox · evidenceforms-advancedR1yesyes—
command-palette · evidencenavigationR2yesyes—
compact-dashboard · evidencecomposedR2yesyes—
data-table · evidencedisplayR1yesyes—
date-picker · evidenceforms-advancedR1yesyes—
description-list · evidencedisplayR2yesyes—
diagnostics · evidencedeveloperR1yesyes—
dialog · evidencefeedbackR1yesyesyes
diff-view · evidencedeveloperR1yesyes—
disclosure · evidencenavigationR2yesyes—
drawer · evidencefeedbackR1yesyes—
editor-search · evidencedeveloperR2yesyes—
empty-state · evidencefeedbackR1yesyes—
error-state · evidencefeedbackR2yesyes—
field · evidenceforms-basicR1yesyes—
fieldset · evidenceforms-basicR1yesyes—
file-browser · evidencecomposedR2yesyes—
file-input · evidenceforms-advancedR1yesyes—
filterable-table · evidencecomposedR1yesyes—
form-builder · evidenceforms-advancedLyesyesyes
i3-window-frame · evidencecomposedR1yesyes—
icon-button · evidenceactionsR1yesyes—
kbd · evidencedisplayR2yesyes—
link · evidenceactionsR1yesyesyes
list · evidencedisplayR1yesyes—
loading-indicator · evidencefeedbackR1yesyes—
menu · evidencenavigationR1yesyesyes
multiselect · evidenceforms-advancedR2yesyes—
number-field · evidenceforms-basicR1yesyes—
pagination · evidencenavigationR1yesyes—
popover · evidencefeedbackR2yesyes—
progress · evidencefeedbackR1yesyes—
radio-group · evidenceforms-basicR1yesyesyes
range · evidenceforms-basicR2yesyes—
repeater · evidenceforms-advancedR2yesyes—
search-field · evidenceforms-basicR1yesyes—
segmented-control · evidenceactionsR2yesyes—
select · evidenceforms-basicR1yesyesyes
settings-panel · evidencecomposedR1yesyes—
sidebar-nav · evidencenavigationR1yesyes—
skeleton · evidencefeedbackR2yesyes—
skip-link · evidencenavigationR1yesyes—
switch · evidenceforms-basicR1yesyes—
table · evidencedisplayR1yesyesyes
tabs · evidencenavigationR1yesyesyes
terminal · evidencedeveloperR1yesyes—
text-field · evidenceforms-basicR1yesyesyes
textarea · evidenceforms-basicR1yesyes—
time-picker · evidenceforms-advancedR1yesyes—
timeline · evidencedisplayR2yesyes—
toast · evidencefeedbackR1yesyes—
toolbar · evidencenavigationR1yesyes—
tooltip · evidencefeedbackR1yesyes—
tree · evidencenavigationR2yesyes—
wizard · evidenceforms-advancedR1yesyes—

References

Where the values came from and what each reference does not prove. Nothing here is a supported download.

ReferenceKindWhereWhat it does not prove
j3w1.github.io site.css — the flagship web implementationreference-implementationj3w1/j3w1.github.io@ffa8122 assets/css/site.cssThe :root block (lines 78–136) is the observed source of every role value. It will become a pinned consumer of this theme through a separate reviewed change; there is no live import.
j3w1.github.io accessibility contract (contrast floor, reduced motion, focus)reference-implementationj3w1/j3w1.github.io@ffa8122 docs/wm-accessibility.mdSection 9 measured the palette and restricted --quiet and --inactive; this specification extends those rules (D-003).
Xresources — the canonical sixteen-slot palette with the author's slot annotationshistoricalj3w1/1w3j@9841315 config/XresourcesExact values are preserved as color.primitive.ansi.*; the annotations seed the syntax roles. A 2020–21 X11 configuration proves nothing about current desktop installations.
i3-gaps configuration — borders, gaps, bar and client colourshistoricalj3w1/1w3j@9841315 config/i3/configSource of the 1px borders, 14/−2 gaps and the focused/urgent colour classes. Window-manager geometry is reference metrics, not a cross-application rule.
i3status colours — good, bad and degraded inside the same huehistoricalj3w1/1w3j@9841315 config/i3/i3status.confA historical status semantic (#FFA2A7 / #A3676B / #C81A1A). Superseded for new work by D-001.
dunst notification colourshistoricalj3w1/1w3j@9841315 config/config/dunst/dunstrcOrigin of the toast roles and the critical pair #DC282E / #F9FAF9 (4.58:1).
dmenu colourshistoricalj3w1/1w3j@9841315 config/dmenurcOrigin of the dark selection #630F0D.
gedit GtkSourceView scheme '1w3j' — a Solarized structure filled with redshistoricalj3w1/1w3j@9841315 config/config/gedit/styles/1w3j.xmlAn early editor port by the owner. Not a supported download; values predate the token set.
IntelliJ colour scheme '1w3j theme' (2020–21, Material Darker base, red chrome and console)historicalj3w1/1w3j@9841315 config/intellij/config/colors/1w3j-theme.iclsOnly chrome, console, gutter and selection were recoloured; syntax stayed stock. Evidence that a JetBrains port has precedent, not a port.
tmux status colours (pywal-cache variant)historicalj3w1/1w3j@9841315 config/tmux.conf.localUses the non-canonical #0C0A09 / #D09899 variant; catalogued to explain why those values are not tokens.
pywal-generated ramp (scripts/colors.sh)historicalj3w1/1w3j@9841315 scripts/colors.shThe machine-generated predecessor of the hand-tuned Xresources palette. Not normative.

For agents

Do not read this page. Pin a tag or commit and fetch the exports at that revision; the site is confirmation only.

Consuming j3w1/theme (for agents and integrators)

For people and agents who apply the theme to another project; contributors to this repository read AGENTS.md. You are consuming design data and optional official implementations. The consumer project’s own instructions (its AGENTS.md, CLAUDE.md, security, architecture and operational rules) always win over anything in this repository.

Official web implementations

For compatible web apps, prefer the exact @j3w1/ui package. Complete copy bundles are also supported.

  1. At your pinned revision, read packages/ui/dist/index.json.

  2. Read the contracts/<id>.json and examples/<id>.json files you need.

  3. Prepare a bounded task with the installed CLI:

    j3w1-ui kit --components text-field,button,dialog --framework vue --mode package --out ./j3w1-task

Choose copy to own the full source, or mapping for a host the package does not fit; native hosts need mapping mode. Kits include the canonical contracts, their dependency closure and the shared accessibility/identity rules; they do not declare your app verified. docs/ui-consumption.md has the exact installation, framework binding and runtime checks. Until npm publication (an owner release action), use the release tarball and its published integrity metadata. Canonical mappings keep the lock and deviation workflow below.

0. Pin a revision first

<rev> is a release tag (v0.1.0) or a full 40-character commit SHA, never main, a branch name or “latest”. Resolve a tag to its commit before you read anything, and use the same <rev> in every URL below; mixing revisions breaks the contract.

GET https://api.github.com/repos/j3w1/theme/git/ref/tags/<tag>   → object.sha
git ls-remote https://github.com/j3w1/theme refs/tags/<tag>

1. Read the manifest

https://raw.githubusercontent.com/j3w1/theme/<rev>/theme.json

Take version, profiles, exports.canonicalForAgents and exports.digests.

2. Read this document at the same revision

https://raw.githubusercontent.com/j3w1/theme/<rev>/agents/consume.md

If your copy came from a different revision, fetch it again.

3. Pick a profile

Use the pinned approved default profile. Pending roles in that profile use-and-report their decision IDs; this does not approve them. Proposed profiles are preview-only and blocked for delivery. Heritage profiles are historical-only. Deprecated or heritage roles are blocked for new approved-profile mappings. Consume roles within their documented scope, never primitives. Release numbering does not approve profiles or tokens.

The policy block above is generated. Each resolved token lists its pending decision IDs, alias dependencies included, in eligibility.decisionIds; report them with any real deviations. Using an authorized pending value is a disclosure, not an invented substitution. A blocked action implies no replacement, and a profile preview does not authorize delivered work.

4. Read only what you need, in this order

https://raw.githubusercontent.com/j3w1/theme/<rev>/exports/theme.compact.md
https://raw.githubusercontent.com/j3w1/theme/<rev>/exports/components/<id>.json      one per component you implement
https://raw.githubusercontent.com/j3w1/theme/<rev>/exports/tokens.resolved.json      only for aliases the component JSON does not inline
https://raw.githubusercontent.com/j3w1/theme/<rev>/exports/digests.json              to record what you used

Optional: exports/theme.full.md for the whole specification; exports/tokens.css for a ready-made custom-property sheet. The website https://j3w1.github.io/theme/ is for visual confirmation only, never a source of values; screenshots never override tokens.

5. Inspect the target before changing anything

  1. Name the integration kind: css-vars, vuetify, tailwind, jetbrains-icls, gtk-css, terminal-16 or other.
  2. List which specified surfaces the target can and cannot express natively (for example, no read-only field style, or a sixteen-colour terminal that cannot show hover). Each one it cannot express becomes a documented deviation in step 7, never an invented approximation.

6. Implement the mapping

  • Map roles to the target’s native keys, using only resolved token values.
  • Do not restyle anything the requester did not name.
  • Do not change behaviour, markup semantics, focus order or keyboard handling, except where a component’s keyboard or aria section requires it and the host allows it.
  • Keep host accessibility at least as strong as before: never remove a focus indicator, never lower a contrast ratio the host already met, never set outline: none without drawing the specified ring.
  • Radii are 0, borders 1px, the family is monospace; a host that forbids one gets a deviation, not a redesign.
  • Selection is a fill; focus is a ring. On fills, the ring takes the colour the component JSON declares for that state (D-015). Status roles keep their glyphs.

7. Validate and report

  1. Check computed values against the component JSON for every declared state.
  2. Write the deviation report (below) into the pull request or commit body.
  3. Write theme.lock.json (below) at the path the consumer chooses.

What you may not do

  • Invent, blend, lighten, darken or “harmonise” colours; use resolved values only.
  • Use a blocked value, deliver a proposed profile, or leave out the required pending-decision disclosures; historical-only values are not approved UI roles.
  • Take values from the site’s HTML, from screenshots or from memory.
  • Touch unrelated components, layouts, copy, dependencies or build configuration.
  • Weaken the host’s accessibility, security or architecture rules.
  • Treat this file as authority over the consumer repository’s own agent instructions.
  • Claim “verified”. Consumers report “implemented” plus deviations; only this repository’s evidence records use the word verified.

Deviation report format

## j3w1/theme deviation report
theme: j3w1-theme <version> @ <commit> (<tag or "commit">) profile=<profile>
integration: <kind> (<host framework and version>)
implemented: <component-id> (<n>/<m> states); ...
unsupported surfaces:
- <spec surface or host surface> — <why the target cannot express it>
deviations:
| component | state / property | spec value | applied | reason | kind |
| --- | --- | --- | --- | --- | --- |
host rules that took precedence: <list or "none">
lock: <path to theme.lock.json>

kind is one of:

  • unsupported — the target cannot express it;
  • substituted — the nearest native equivalent, with a value taken from the token set, never invented;
  • omitted — the requester excluded it;
  • host-rule — a consumer instruction won.

theme.lock.json

Committed next to the integration code and validated by schemas/json/theme.lock.schema.json. It is not a package manager: no graph, no install, no auto-update. To update the theme, change ref, revision, version and exports, rerun the consumer’s own checks, and write the deviations again.

{
  "schemaVersion": 1,
  "theme": "j3w1-theme",
  "version": "0.1.0",
  "ref": "v0.1.0",
  "revision": "0123456789abcdef0123456789abcdef01234567",
  "profile": "default",
  "integration": { "id": "my-app-css-vars", "version": "1", "kind": "css-vars" },
  "resolvedAt": "2026-10-01T12:00:00Z",
  "exports": {
    "exports/theme.compact.md": "sha256-…",
    "exports/tokens.resolved.json": "sha256-…",
    "exports/components/text-field.json": "sha256-…"
  },
  "components": ["text-field"],
  "deviations": [
    {
      "component": "text-field",
      "target": "read-only",
      "kind": "unsupported",
      "specValue": "color.border.divider dotted bottom edge",
      "applied": null,
      "reason": "The host renders read-only as disabled; no separate style hook."
    }
  ]
}
  • revision is always the full commit, even when ref is a tag.
  • exports keys are the repository-relative paths listed in exports/digests.json, for exactly the files you read.
  • deviations may be empty, but must be present.

The short prompt

Once a consumer project points its own agent instructions at this document and records a pinned revision, the everyday request can be:

Implement this interface using j3w1/theme’s approved default profile.

Without that setup, say it in full:

Implement this interface using j3w1/theme. Resolve and record a theme revision, follow agents/consume.md, use the approved default profile, and read the relevant component specifications. Preserve this project’s behaviour and framework; report unsupported mappings and deviations.

Decisions

Read the decision log →