Skip to content
ThemesCraft.

A theme.json Architecture That Survives Six Client Handovers

Tokens, layers, and the naming convention we landed on after breaking it three times. Includes the starter file we now begin every project with.

A theme.json Architecture That Survives Six Client Handovers

theme.json is a design system contract disguised as a config file. Treated casually it becomes a thousand-line dumping ground. Treated as an architecture it removes most of the CSS you'd otherwise write.

Three layers, no exceptions

We split every project's tokens into primitives, semantics, and components. Primitives are raw values. Semantics map meaning onto them. Components are the only place a block name may appear.

Naming, so a stranger can read it

  • Primitives: base-sand-100, base-ink-900, scale-4
  • Semantics: surface, surface-raised, text, text-muted, accent
  • Components: styles.blocks.core/button, styles.blocks.core/quote

Why editors break things

If your palette exposes fourteen colours, an editor will use fourteen colours. Expose five semantic slots with sensible names and the site stays coherent two years after you've stopped invoicing for it.

Constrain the palette, not the person. Nobody has ever thanked a theme for offering them 'Accent 7'.

Version it like code

We keep theme.json under review in the same PR as the markup that consumes it, and we diff generated CSS output in CI. A token rename that adds 6kb to the payload fails the build.