All articles
Design Tokens

How to Build a Token Design System That Holds

JUL 2, 2026 · 7 min read · Subin

A token system is not a palette with nicer names. It is a contract between design and code that says: every visual decision lives in exactly one place, and everything downstream refers back to it.

Names are not tokens

Renaming #FF7A00 to ember-500 changes nothing on its own. You still have a raw value that a component can hardcode, and a hundred places that can drift from it. A token becomes useful only when it is a reference that resolves, not a label you paste.

The unit of value in a token system is the reference. brand-button-bg does not contain a color; it points at accent, which points at ember-500. Change the primitive and the button follows, because it never held a color of its own.

Primitive
What values exist
carbon-900 = #0E0F12, ember-500 = #FF7A00, space-4 = 16px. Raw, named, opinion-free.
↓ referenced by
Semantic
What they mean
--surface = carbon-900, --accent = ember-500, --danger = scarlet-500. Intent, not hex.
↓ referenced by
Component
Where they apply
button-bg = --accent, card-surface = --surface. Each layer only points at the one below it.
Three layers, each referring only to the one below. Values live at the bottom; meaning and application sit above.

The three layers, and why order matters

Primitives answer what values exist: the raw ramps, named and opinion-free. Semantic tokens answer what they mean: surface, accent, danger, the intent behind a choice. Component tokens answer where they apply: button background, card surface, input border.

The rule that makes it hold is strict: each layer may reference only the layer beneath it. Components never touch primitives. Semantics never touch components. Break that rule once and you have reintroduced the coupling tokens were meant to remove.

Design for the states, not just the swatchesMost drift comes from missing tokens, not careless ones. A hovered destructive button, a disabled input on a raised surface: if the token does not exist, someone invents a value. Enumerate the real states first and the shortcuts disappear.

Modes are just another axis

Light and dark, comfortable and compact, brand A and brand B: these are not separate token sets, they are modes of the same semantic layer. surface resolves to one primitive in light and another in dark. The component never knows which mode it is in, and never has to.

That is the whole payoff. A theme change becomes a swap at the primitive level, and it ripples up automatically through semantics and components to every screen.

Source
Figma variables
Collections and modes hold every decision once.
Build
Token transform
Export on publish, generate the platform files.
Output
Platform tokens
WebiOSAndroid
The source lives in Figma variables; a build turns it into platform tokens. Design review and code review become the same review.

A token system that holds

  1. One source of truth for values, never a designer's memory.
  2. Three layers, each referencing only the one below.
  3. Semantic names for intent, so screens survive rebrands.
  4. Modes as an axis of the semantic layer, not duplicate sets.
  5. Generated into code on publish, and linted so raw values fail review.

Where teams get the layers wrong

The most common mistake is letting a component reference a primitive directly, skipping the semantic layer because it is quicker in the moment. It works until the rebrand, when that one component ignores the new theme because it was pointing at a raw value the whole time. One shortcut, one screen that will not re-theme.

The second mistake is a semantic layer that just renames primitives one to one: surface equals gray-900 and nothing more. Semantics earn their place by encoding intent that can change per mode, not by being an alias with extra steps. If your semantic layer has no modes, it is not yet doing its job.

A token is not a value with a nicer name. It is a promise that the value lives somewhere else.On token architecture