Tags: web-dev concept

Design Tokens

Date: 2026-08-16


Named values for design decisions, stored independently of any implementation. The contract between design and code — and the whole benefit comes from the naming layer, not from the values.


Design tokens are the design decisions of a system — colour, spacing, type, radius, shadow, duration — extracted into named values that every implementation references rather than hard-codes.

Storing #1d4ed8 in a JSON file achieves nothing. Storing it as colour.action.default is the entire idea, because now the name can outlive the value.

The three tiers

The mechanism that makes tokens worth having. Skip it and you have a variables file.

PRIMITIVE          raw values, no meaning
  blue.600    #1d4ed8
  red.500     #ef4444
  space.4     16px

SEMANTIC           meaning, not appearance
  colour.action     → blue.600
  colour.danger     → red.500
  space.inset.md    → space.4

COMPONENT          scoped to one thing
  button.bg.default → colour.action
  button.padding    → space.inset.md

Each tier answers a different change:

rebrand         → change PRIMITIVES only
dark mode       → change SEMANTIC mappings
button tweak    → change COMPONENT tokens

That’s the payoff. A rebrand touches one file of hex codes; a component never referenced a hex code in the first place.

What goes wrong without the semantic tier

The common failure is stopping at primitives and using them everywhere:

BEFORE                    AFTER A REBRAND
.btn   { bg: blue.600 }   find/replace across
.link  { c:  blue.600 }   the whole codebase,
.focus { o:  blue.600 }   deciding each case
.badge { bg: blue.600 }   individually

Every one of those blue.600 uses meant something different — action, navigation, focus indicator, status. They only looked identical because the brand happened to make them so, and the rebrand is where that collapses.

With semantics, focus stays focus when the brand blue changes.

Naming

The hard part, and the part that decides whether anyone uses them.

  • Name by role, not appearance. colour.danger survives; colour.red doesn’t — Colour Systems
  • A consistent grammar. category.role.variant.state or similar, applied without exception. Inconsistency here is what makes a token set unbrowsable
  • Don’t encode the value. space.16 is fine as a primitive; padding.16px in a component is a hard-coded value wearing a costume
  • Resist over-tokenising. A token for every property of every component is a second codebase with none of the tooling

Format and delivery

Tokens are stored once and transformed for each target.

tokens.json
    ↓  build step
├─ CSS custom properties   web
├─ SCSS variables          legacy web
├─ JS / TS object          runtime access
├─ iOS / Android           native
└─ back into the design tool

The W3C Design Tokens format is the emerging interchange standard, which matters because it’s what lets design tools and build tools agree — Design Tokens in Practice.

[CHECK: current status of the W3C Design Tokens Community Group specification before depending on it.]

What tokens can’t do

  • They don’t make things consistent. They make consistency possible. A developer can still write padding: 13px
  • They don’t capture composition. “This card uses medium inset spacing and a subtle shadow” is a component decision, not a token
  • They rot like anything else. A token nobody references is still shipped, still documented, and still suggests it’s supported — Component Inventory

Where to draw the line

Tokenise a value when the same decision appears in more than one place and would need to change together. That’s the test.

A one-off value used in one component is not a token; it’s a value. Adding it to the system creates a maintenance obligation in exchange for nothing — Design Systems.