Skip to main content

The design tokens format, explained

What this is

The W3C Design Tokens Community Group publishes a format module that says how a design token is written down, so a file can move between Figma, a build tool and every platform without anyone rewriting it. This page is a readable reference for version 2025.10: the thirteen types, a copyable example of each, and the parts people get wrong. Everything here is taken from the validator that ships in the CLI, so it matches what a real tool accepts.

The shape of a token

A token is an object with a $value and, in almost every case, a $type. Keys beginning with a dollar sign are reserved by the spec; every other key is a name you chose.

tokens.json
{
  "color": {
    "brand": {
      "500": {
        "$type": "color",
        "$value": { "colorSpace": "srgb", "components": [0.22, 0.74, 0.97] },
        "$description": "Primary interactive colour"
      }
    }
  }
}

Any object without a $value is a group. Groups nest as deeply as you like and can set a $type that every token inside them inherits, which is how most real files avoid repeating the type on every line.

What 2025.10 changed

The change that breaks older files is colour. A colour value is now an object naming its colour space and its components. A bare hex string is no longer a valid colour value, and a validator will reject it.

No longer valid

{
  "$type": "color",
  "$value": "#38bdf8"
}

2025.10

{
  "$type": "color",
  "$value": {
    "colorSpace": "srgb",
    "components": [0.22, 0.74, 0.97]
  }
}

The reason is that a hex string only ever meant sRGB, and design systems have moved past it. Seven colour spaces are admitted: srgb, hsl, hwb, lab, lch, oklab, oklch. Components are numbers in that space's own range, an optional alpha runs 0 to 1, and an optional hex may be carried alongside as a fallback for tools that cannot read the rest.

Aliases

A token can point at another token instead of holding a value. The reference is the token's path in curly braces. This is what makes a semantic layer possible: the semantic token names the purpose, the primitive holds the number, and a theme swap changes one file.

Alias
{
  "$type": "color",
  "$value": "{color.brand.500}"
}

The seven base types

Each of these holds a single value. Eight, counting strokeStyle, which can be either a keyword or an object.

color

A colour, as a colour space and its components. Not a hex string.

{
  "$type": "color",
  "$value": {
    "colorSpace": "srgb",
    "components": [0.22, 0.5, 0.85],
    "alpha": 1,
    "hex": "#3880d9"
  }
}
dimension

A length, as a number and a unit. px and rem only.

{
  "$type": "dimension",
  "$value": { "value": 16, "unit": "px" }
}
fontFamily

A family name, or an array of them as a fallback stack.

{
  "$type": "fontFamily",
  "$value": ["Inter", "system-ui", "sans-serif"]
}
fontWeight

A number from 1 to 1000, or one of the named aliases.

{
  "$type": "fontWeight",
  "$value": 600
}
duration

A length of time. ms or s.

{
  "$type": "duration",
  "$value": { "value": 200, "unit": "ms" }
}
cubicBezier

Four numbers: the two control points of an easing curve.

{
  "$type": "cubicBezier",
  "$value": [0.4, 0, 0.2, 1]
}
number

A bare number, for anything with no unit of its own.

{
  "$type": "number",
  "$value": 1.5
}
strokeStyle

A named stroke, or a dash array with a line cap.

{
  "$type": "strokeStyle",
  "$value": "dashed"
}

The five composite types

A composite type holds several sub-values under one name, and each sub-value can itself be an alias. This is where a token stops being a number and starts being a decision.

border

A colour, a width and a style, together.

{
  "$type": "border",
  "$value": {
    "color": "{color.border.default}",
    "width": { "value": 1, "unit": "px" },
    "style": "solid"
  }
}
transition

A duration, a delay and an easing curve.

{
  "$type": "transition",
  "$value": {
    "duration": { "value": 200, "unit": "ms" },
    "delay": { "value": 0, "unit": "ms" },
    "timingFunction": [0.4, 0, 0.2, 1]
  }
}
shadow

One shadow, or an array of them for a stack.

{
  "$type": "shadow",
  "$value": {
    "color": "{color.shadow.subtle}",
    "offsetX": { "value": 0, "unit": "px" },
    "offsetY": { "value": 2, "unit": "px" },
    "blur": { "value": 8, "unit": "px" },
    "spread": { "value": 0, "unit": "px" }
  }
}
gradient

An array of colour stops, each with a position from 0 to 1.

{
  "$type": "gradient",
  "$value": [
    { "color": "{color.brand.500}", "position": 0 },
    { "color": "{color.brand.900}", "position": 1 }
  ]
}
typography

A whole text style in one token.

{
  "$type": "typography",
  "$value": {
    "fontFamily": "{font.family.base}",
    "fontSize": { "value": 16, "unit": "px" },
    "fontWeight": 400,
    "letterSpacing": { "value": 0, "unit": "px" },
    "lineHeight": 1.5
  }
}

Font weight names

A fontWeight is a number from 1 to 1000, but ten keywords are accepted as well and map onto the usual hundreds: thin, hairline, light, normal, regular, book, medium, bold, black, heavy.

Checking a file

Reading a spec tells you what should be true. A validator tells you whether it is. Paste a token file into the DTCG validator and it reports structure, type, value, naming and reference errors against 2025.10, in the browser, with nothing uploaded anywhere.

If you do not have a file yet, the CLI writes one from any live URL, which is a faster way to see a real, valid document than writing one by hand.

terminal
npx dembrandt your-site.com --dtcg