Design tokens: decisions with a name

It is easy to reduce design tokens to a technical detail: variables that hold colors and sizes. But that reading misses the point. A token is a design decision with a stable name.

The difference is in the name. #1a1a1a is data. color-text-primary is a decision: this is the color we use to speak to the user in the foreground. The value can change; the decision stays.

Three layers, three responsibilities

A healthy token system is usually organized in layers, and each one answers a different question:

  1. Primitiveswhat values exist? A raw palette: gray-900, blue-500, space-4. They mean nothing on their own.
  2. Semanticwhat do they mean? color-text-primary, color-surface, space-inset. This is where intent lives.
  3. Componenthow are they applied here? button-background, card-padding. They tie intent to a specific context.

The rule that keeps everything in order is simple: a layer may only refer to the previous one. Components never point at a primitive directly.

The real benefit: the dark mode you didn’t design twice

When components consume semantic tokens, dark mode stops being a redesign and becomes a remap:

:root {
  --color-surface: #ffffff;
  --color-text-primary: #1a1a1a;
}

@media (prefers-color-scheme: dark) {
  :root {
    --color-surface: #101010;
    --color-text-primary: #e9e9e7;
  }
}

No component changed. What changed is what its decisions mean in a different context. That is a token doing its job: absorbing change so nothing else has to know about it.