Skip to content
juniordev4life
Go back

Design Tokens Are a Contract Too

Search your component code for # right now. How many raw hex values come back? Twenty? Two hundred?

Every one of those is a small, private decision about your brand, made in a component, invisible to your design team, and impossible to change centrally. It is the theming equivalent of the specificity wars I wrote about in the cascade layers post - and it has the same root cause: a shared concern with no agreed structure, so everyone improvises locally.

Design tokens fix it. But only if you treat them for what they actually are: the API between design and development - and like every API, an API needs a contract.

Tokens are an interface, not a variable dump

The common failure is treating tokens as “our colors, but in variables”. That gives you a big flat list - blue, blue-dark, blue-new, blue-final - and all you have really done is move the chaos into :root.

An interface has structure. For tokens, the structure the industry has converged on is three layers, each referencing only the layer below:

:root {
  /* 1. Primitive — raw values. No meaning, just facts. */
  --blue-500: #2563eb;
  --grey-900: #111827;

  /* 2. Semantic — meaning. What is this colour FOR? */
  --color-action-primary: var(--blue-500);
  --color-text-default: var(--grey-900);

  /* 3. Component — scoped decisions for one UI element. */
  --button-bg-primary: var(--color-action-primary);
}

The rule that makes it work is the strict one-way flow: primitive → semantic → component, never backwards, never sideways. Break that and you get circular references that ruin both build-time optimization and your ability to reason about a change.

And that discipline buys something concrete. Change --blue-500 once and it cascades everywhere the brand blue appears. Decide that “primary action” should no longer be blue, and you edit exactly one semantic line - no component ever notices the primitive moved beneath it.

Why the semantic layer earns its keep

If you only take one thing from this post, make it the middle layer, because it is the one teams skip - and it is the one that pays for itself.

Consider dark mode. With raw values or primitive tokens sprinkled through components, dark mode is a rewrite: hunt every colour, decide a counterpart, hope you found them all. With a semantic layer, it is a remapping:

[data-theme="dark"] {
  --color-text-default: var(--grey-100);
  --color-action-primary: var(--blue-300);
}

The components change nothing. They asked for “the default text colour” - the meaning stayed identical while the value changed. The same holds for a rebrand, a high-contrast mode, or a white-label tenant. The semantic layer is where your design intent lives, and intent is far more stable than any hex value.

Tokens are mainstream now, by the way: adoption jumped to roughly 84% of teams in a 2026 industry survey (up from 56% a year earlier), and the W3C Design Tokens Community Group shipped a stable format module backed by Adobe, Google, Meta, and Figma. This is no longer an experiment - which makes doing it properly more urgent, not less.

The contract part

Here is where most token systems quietly fail. The naming got designed; the governance never did. And an API without governance is not a contract - it is a suggestion.

Four things turn a token set into a contract:

  1. One source of truth, consumed by both sides. Tokens live in a versioned package that design tooling and every application consume. If a colour exists in Figma but not in the package, it does not exist. If someone hardcodes a hex, it is a contract violation - not a style preference.
  2. Ownership. Somebody owns the token set: reviews changes, keeps the naming coherent, says no to --blue-new-2. An unowned token set becomes a landfill in about six months.
  3. Versioned, deprecation-first changes. A token change is a release, and a removal is a deprecation first. Renaming a semantic token across twenty apps in one afternoon is a breaking change - treat it like one, exactly as you would with any public API.
  4. Automated checks. Contrast checks in CI so a “small tweak” cannot silently break accessibility. Breaking-change detection so a removed token fails a build rather than a customer’s screen.

That last point matters especially because tokens and accessibility are the same conversation. A pair of semantic tokens is where your contrast ratio actually lives; automate the check there and the whole system inherits it.

Enforce it where the drift happens

The contract needs teeth at review time, not just in a document. The cheapest enforcement is a lint rule that rejects raw values in component code:

// stylelint — no hardcoded colours outside the token layer
{
  "rules": {
    "color-no-hex": true,
    "declaration-property-value-allowed-list": {
      "/^(color|background|border)/": ["/^var\\(--/"],
    },
  },
}

Now “use the tokens” is not a code-review opinion someone has to enforce socially. It is a failing build - and the review conversation moves up a level, to the question that actually needs a human: is this the right semantic token for this element? (The same shift I described for cascade layers: reviews stop arguing about mechanics and start discussing meaning.)

Keep it small, or it rots

One warning, because I have watched this happen. Token sets rot exactly like documentation does - by accumulation. Every special case adds a token, every campaign adds a colour, and eventually you have four hundred tokens, nobody knows which to use, and people start hardcoding again because guessing is faster than searching. At that point the system has failed, quietly, while looking impressive.

Keep the semantic layer deliberately small. Fewer, well-named tokens beat exhaustive coverage. If a value is used once, it probably does not need a token - and if two tokens mean nearly the same thing, one of them should not exist.

The blueprint legend

Look at an architectural blueprint. Every wall, door, and outlet is drawn with standard symbols, and in the corner sits a small legend explaining what each symbol means. That legend is unglamorous - nobody frames it - but it is what lets an architect in one city, an electrician in another, and an inspector who arrives a year later all read the same drawing and reach the same conclusions. The building gets built correctly because everyone agreed, up front, what the marks mean.

Design tokens are that legend for your product. The primitives are the ink; the semantic layer is what each mark means; the components are the drawing. And the governance - the ownership, the versioning, the checks - is what keeps the legend true as the building changes.

Draw the legend once, together, and keep it honest. Skip it, and everyone starts inventing their own symbols - and nobody, least of all the person who joins next year, can read the plan anymore.


Share this post:

Next Post
Green Web, Hungry AI - An Honest Sustainability Reckoning