Skip to content

Theme builder

Pick one brand color and this builder derives the rest of the data-color accent set — the hover shade, the soft tint, and the text-on-primary color — checks the WCAG contrast for you, and generates ready-to-use exports.

Two modes:

  • Accent — adds a new [data-color="<name>"] axis (opt-in, sits alongside the built-in five). Just the accent changes.
  • Full theme — customises the default look: accent plus a neutral ramp (gray / slate / zinc / neutral / stone, driving surface / text / border / secondary), the control radius, and typography (body / heading / mono font-family), across both light and dark. The output is computed as the diff of the themed build against the stock build, so it’s exactly the variables that changed — nothing more.

It works by running the real token transformer (@hypermedia-components/core/token-transform) on the real DTCG sources right in your browser. The preview, the Apply to this page button, and every export are produced by the same buildTokensCss the library build uses — so a custom theme behaves exactly like a built-in one (every affected component variable, subtree-safe), and the “DTCG sources → generated CSS variables” model is never bypassed.

Active Neutral
Saved

Semantic status colors (success / warning / error) stay fixed — the accent doesn't touch them.

Heading sample

Body text on this ramp — press ⌘K (mono). Select me for ::selection.

Scoped to this box and rendered by the real token build. Toggle the site's light/dark switch to check both. Apply to this page themes the whole site.

Additive — keep the stock CSS and load this after it. No build.

OutputDerivation
action-primary-bg / borderYour chosen brand color, as-is.
action-primary-hover-bg / borderBrand color darkened toward black by the Hover darkness percentage.
action-primary-fgAuto picks white or gray.900 (#111827) — whichever has the higher contrast against the brand color. Override it manually if you prefer.
action-primary-soft-bgcolor-mix(in srgb, <brand> N%, transparent) — one value that blends correctly on light and dark surfaces.
focus-ringDefaults to the brand color.

The contrast read-out is the WCAG 2.x ratio between the brand color and the resolved text color. Aim for 4.5 : 1 (AA) or better; the badge turns red below that.

The builder runs buildTokensCss with your color injected as a synthetic color.<name> source, then hands you the output three ways:

  1. Theme CSS block — just this theme’s [data-color="<name>"] block (every affected component variable, resolved). Additive: keep the stock token CSS and load this after it, then set data-color="<name>". No build. This is the correct Path A — overriding the seven semantic variables by hand would not work (see How the cascade actually works).

  2. DTCG token filecolor.<name>.tokens.json. Save it under packages/core/src/tokens/ and register it in build-tokens.mjs to ship the theme in the build (Path B). Also feeds external DTCG tooling (Style Dictionary, Figma).

  3. Full token CSS — the complete hc.tokens.css (every built-in theme plus yours). A drop-in replacement for the stock token stylesheet when you’d rather swap one file than add a block.

Apply to this page injects the generated block onto the docs site’s <html> so you can browse every component under your theme; Reset clears it.

  • Color themes — the built-in five, the cascade explanation, and the full authoring guide.
  • Density — orthogonal sizing axis.
  • Tokens overview — the four-layer model.