Design system

Designing with tokens, not values

Scott 5 min read

A theme is a set of names that point to values. The names are stable. The values move.

The trick

Inside theme.json, references look like names, not values:

"buttonStyles": {
  "primary": {
    "bg":    "primary",   // → var(--color-primary)
    "color": "bg",        // → var(--color-bg)
    "hover": { "bg": "secondary" }
  }
}

If you change colors.primary from green to indigo, the button changes — and so do the link color, the focus ring, the eyebrow text, the article blockquote border, and the inverse text on the brand color scheme. One change, one source of truth, dozens of effects.

Scales, not sizes

Spacing, fonts, radius — all live on the same scale:

xxs · xs · sm · md · lg · xl · xxl · xxxl

Authors pick names, not pixels. A block asking for paddingX: "lg" stays in sync with whatever --space-lg resolves to.

Color schemes layer cleanly on top

Because every themed element references var(--color-*), a single attribute swaps the palette inside its scope:

<section data-scheme="dark"> … </section>

Inside, the same buttons, links, and text re-skin automatically. No per-block overrides.

What this is not

  • It's not a runtime themer. The CSS is generated once at build time.
  • It's not a component library. It's a small set of utilities driven by JSON.
  • It's not a CSS-in-JS layer. It's CSS files plus design tokens.

Tokens are the API of your design system. Values are its implementation.

Up next: how the prototype came together in a single session.