Design tokens: names instead of numbers

Why:You’ll learn to keep colors, spacing and radii as named decisions in three layers (base, semantic, component) and to write them in the W3C DTCG format. Afterwards your page has a tokens file and the same tokens as CSS variables, and one change of a base color changes the whole page.

30 minutes

Read by speech synthesis (Qwen3-TTS); the voice is not a person’s.

A design token is a named design decision, such as the main action’s color, kept apart from any platform. W3C’s DTCG is a shared JSON format for token files.

A name instead of a number

The words “this blue” mean one thing on a page and another in a developer’s head. One person writes #0b5cad, another #0c5cae, a third “a bit darker”. Instead you can decide once, “this is the color of the action”, give the decision a name, and refer to the name everywhere. A named design decision is called a design token.

A token is not the same as a CSS variable. A variable is a mechanism: a way to store a value on a page. A token is an agreement: the decision has a name, a value, a meaning and an owner, and it is kept independently of the platform. From one tokens file you get CSS variables for the site, variables for Figma, and values for an app on a phone. So two systems where everything is named with tokens can be brought into one look without rewriting by hand.

Check yourself: how does a token differ from a CSS variable?

A variable is a way of storing on a page. A token is a named decision kept independently of the platform: from it you get variables for the site, for Figma and for apps.

Three layers

If you name tokens simply by color (“blue-600”), you won’t survive a change of theme: the button will stay blue. So tokens are put in three layers, and each refers to the one below.

  1. Base (primitive). Raw values: color.accent.600 equals #0b5cad, space.4 equals 16 pixels. This is the “palette” and the “ruler”. Base tokens are named by look.
  2. Semantic (also called alias). Roles: semantic.action (the color of the main action), semantic.surface (the background), semantic.text (the color of text). They refer to base tokens and are named by role.
  3. Component. Values for a particular part: component.button.bg (the button’s background) refers to semantic.action.

Why this way? Change the base accent color: the semantic token that refers to it changes, and after it every component that refers to the semantic one. Change the theme: for the semantic tokens surface and text you swap the reference to other base values, and don’t touch the components at all, because they refer to roles and not to colors.

Play with it: change the base color, choose another step for the action and switch the theme. On the left is the tokens file, on the right the chain of references and the result.

Three layers of tokens: a change at the bottom reaches the very top
semantic.action refers to:
{
  "color": {
    "$type": "color",
    "accent": {
      "500": {
        "$value": "#3c7dbd"
      },
      "600": {
        "$value": "#0b5cad"
      },
      "700": {
        "$value": "#084582"
      }
    },
    "neutral": {
      "50": {
        "$value": "#faf9f7"
      },
      "900": {
        "$value": "#1c1b19"
      }
    }
  },
  "semantic": {
    "$type": "color",
    "action": {
      "$value": "{color.accent.600}"
    },
    "surface": {
      "$value": "{color.neutral.50}"
    },
    "text": {
      "$value": "{color.neutral.900}"
    }
  },
  "component": {
    "button": {
      "bg": {
        "$type": "color",
        "$value": "{semantic.action}"
      },
      "fg": {
        "$type": "color",
        "$value": "{semantic.surface}"
      }
    }
  }
}

A project card

Main action
The chain of references and the final value
component.button.bg→ {semantic.action}#0b5cad
component.button.fg→ {semantic.surface}#faf9f7
semantic.action→ {color.accent.600}#0b5cad
semantic.surface→ {color.neutral.50}#faf9f7
semantic.text→ {color.neutral.900}#1c1b19

Real systems do the same. In Material Design 3 the three layers are called reference, system and component. In Fluent 2 they are global tokens and aliases. At Atlassian a name is made of a property, a role and a state: color.text.accent.red.

Check yourself: how do you change a theme without touching components?

Redefine the semantic layer: surface and text refer to other base values. Components refer to roles and are recolored by themselves.

How to name tokens

Rules that help you not to get lost:

  • Semantic and component tokens by role, base tokens by look. Not color.dark-gray but color.text.primary: the dark gray can be replaced, and the role stays.
  • A hierarchy from left to right, from general to particular: color, then text, then primary.
  • States as a separate word: hover, pressed, disabled.
  • A scale in numbers for base steps (50, 100, … 900) and for spacing (space.2, space.4).
  • Don’t hide meaning in a number. The name space.4 is better than space.16: if the step changes, the name doesn’t become a lie.

The W3C DTCG format

So that every tool understands a tokens file, there is a common format. It is developed by the W3C Design Tokens Community Group, a community of developers, designers and tool makers. In October 2025 the first stable version of the format came out (2025.10).

The file is JSON. The recommended extension is .tokens.json. The structure is:

  • A token: an object with a $value property (required) and optional $type (the type) and $description (an explanation).
  • A group: an object without $value, holding tokens and nested groups. A type can be set on a group, and then it is inherited.
  • A reference to another token: a value in curly braces, for example "{color.accent.600}".
  • Types: color, dimension, fontFamily, fontWeight, duration, cubicBezier, number and composite ones (shadow, border, typography and others).
{
  "color": {
    "$type": "color",
    "accent": { "600": { "$value": "#0b5cad" } }
  },
  "semantic": {
    "$type": "color",
    "action": { "$value": "{color.accent.600}" }
  }
}

A caveat about how values are written. In early drafts a color was a string ("#0b5cad") and a size was a string ("16px"). The stable version 2025.10 describes a color as an object with a color space and components (colorSpace, components, optionally hex), and a size or a time as an object of a number and a unit: { "value": 16, "unit": "px" }. Many files and tools still use the short form, so you will meet both. In the practice we use the short form, so as not to work out color components by hand.

From a tokens file a program such as Style Dictionary makes output files for each platform: CSS variables, values for iOS and Android. For a small site it is enough to write the variables by hand, repeating the structure of the file.

Tokens in CSS

In CSS the layers repeat the structure of the file: first the base ones, then the semantic ones through var(), then the component ones.

:root {
  --color-accent-600: #0b5cad;
  --action: var(--color-accent-600);
  --button-bg: var(--action);
}
[data-theme="dark"] {
  --surface: var(--color-neutral-900);
}

Now every rule refers to var(--button-bg) and not to a color. If a “raw” color is left in the CSS somewhere outside the block of variables, a token has been missed: check that yourself by searching the file.

Check yourself: what is required of a token in the DTCG format?

The $value property. The $type is optional, and it can be inherited from the group.

A live example: this textbook’s tokens

The textbook’s own tokens are arranged the same way. Open the file design/tokens.css in the repository: it wasn’t written by hand but derived from a tokens file in the DTCG format in the NoeticEcho project (where from and how is recorded in design/PROVENANCE.md). It has the same layers. Base values are named by look and step (--ink-100, --paper-100, --brass-500). Semantic ones are named by role (--surface-canvas, --text-primary, --accent-command) and refer to base ones through var(). And where the author decided something, a comment is left: for example, the text color has a separate, lighter step, because the original color failed the contrast check on a dark panel. The decision is written down in a name and in a file, not in the author’s head.

Practice

Build your project’s tokens in two forms. First complete the file in the DTCG format (it sits right on the page as a script block of type application/json; it won’t be on the finished site, because it is marked data-scaffold). Then repeat the same tokens as variables in styles.css and make a dark theme by redefining only the semantic layer.

When the checks pass, change --color-accent-600 and watch how both buttons are recolored. If one stays as it was, a “raw” color is left somewhere.

What was wrong with 2014

In 2014 there were almost no variables in CSS: colors were repeated in twenty places, and for “variables” people used preprocessors such as Sass and Less, which substituted the values before the page reached the browser. Native CSS variables had only just arrived in Firefox, and in all the main browsers they worked by 2017. And there was no common format for tokens at all: every system invented its own.

Practice

Preparing your page…

Test

Question 1 of 6

Put the three layers of tokens in order, from the lowest to the highest

Put them in order with the “up” and “down” buttons.

Cards

These cards go into your review once you finish the lesson.

  • What is a design token?

    Answer

    A named design decision kept apart from any platform: from a tokens file you get CSS variables, Figma values and code for apps.

  • What are the three layers of tokens?

    Answer

    Base (raw values), semantic (roles: action, surface, text), component (button.bg). Each layer refers to the one below.

  • What does a token look like in DTCG?

    Answer

    JSON with a required $value and an optional $type; a reference to another token goes in curly braces: {color.accent.600}. The first stable version of the format came out in October 2025 (2025.10).

  • How do you change a theme through tokens?

    Answer

    Redefine only the semantic layer: surface and text take other base values. Components refer to roles and are recolored by themselves.

  • How do you name tokens?

    Answer

    By role and place, not by look: color.text.primary, not color.dark-gray. Then the value can change and the name stays true.

Sources

Videos

Quick intro to Design Tokens (Penpot)

The video loads from youtube-nocookie.com only when you press play.

Open on the site

Next

You now know: design tokens, the W3C DTCG token format.