Design Tokens: The Complete Guide
Design tokens are named values that encode visual decisions. DESIGN.md organizes them into four frontmatter maps (colors, typography, spacing, rounded) plus a components section that references them with a {path.to.token} syntax. From there, the CLI exports to a Tailwind v4 @theme block, plain CSS custom properties, or a DTCG JSON file in a single command.
What design tokens are#
A design token is a name-value pair that replaces a hardcoded value with a shared, documented decision. Instead of #3B82F6 scattered across forty files, you define it once and reference the name everywhere. The token carries intent (tertiary signals "interactive element"); the raw hex value does not.
Tokens let you:
- Update a value in one place and propagate it to every consumer.
- Communicate purpose through naming rather than raw values.
- Export to multiple target formats (CSS custom properties, Tailwind theme, W3C DTCG) from one source of truth.
In a DESIGN.md, the colors, typography, spacing, and rounded maps hold tiers 1 and 2, components is tier 3, and {...} references wire tier 3 back to the values beneath it.
The three-tier model#
The widely-taught community model splits tokens into three tiers. DESIGN.md covers all three.
Tier 1: Global tokens (primitive / raw)#
Global tokens enumerate the raw palette. They have no opinion about usage; they just record what values exist. Renaming them is a breaking change.
colors:
blue-500: "#3B82F6"
gray-900: "#111827"
red-600: "#DC2626"
DESIGN.md can hold global tokens under colors, spacing, and rounded, though the spec defaults to semantic names at this tier.
Tier 2: Semantic tokens (alias / role)#
Semantic tokens map an intent onto a value. They answer "where is this used?" rather than "what color is this?"
colors:
primary: "#111827" # dominant text, main brand chrome
secondary: "#6B7280" # supporting text, metadata
tertiary: "#3B82F6" # interactive elements, CTAs
surface: "#FFFFFF" # card and panel backgrounds
on-surface: "#111827" # text placed on a surface
error: "#DC2626" # destructive actions, error states
DESIGN.md works at this tier by default. The spec recommends the seven names above (primary, secondary, tertiary, neutral, surface, on-surface, error) because agents and exporters recognize them. Missing a primary key when colors are otherwise defined triggers a missing-primary warning.
Tier 3: Component tokens#
Component tokens bind semantic values to a specific UI element. They are the most specific tier and the most frequently changed.
components:
button-primary:
backgroundColor: "{colors.tertiary}"
textColor: "#ffffff"
typography: "{typography.label-md}"
rounded: "{rounded.md}"
padding: 12px
button-primary-hover:
backgroundColor: "{colors.secondary}"
The {colors.tertiary} notation is the DESIGN.md reference syntax. A reference that points to a key that does not exist triggers a broken-ref error at lint time.
How DESIGN.md expresses each token type#
Colors (colors)#
Color tokens are name-to-color pairs under the colors key. Any CSS color string is accepted (hex, named colors, rgb(), hsl(), oklch(), color-mix(), and more); six-digit hex (#RRGGBB) is the recommended default, and every export format converts colors to lowercase hex.
colors:
primary: "#1A1C1E"
secondary: "#6C7278"
tertiary: "#B8422E"
neutral: "#F7F5F2"
The linter runs a WCAG AA contrast check (4.5:1 minimum) on every component pair that has both a backgroundColor and a textColor. Full details: Colors reference.
Typography (typography)#
Typography tokens are named objects. Each object can carry up to seven sub-fields:
All sub-fields are optional. Spec-recommended token names: headline-display, headline-lg, headline-md, body-lg, body-md, body-sm, label-lg, label-md, label-sm. Full details: Typography reference.
Spacing (spacing) and Rounding (rounded)#
Both are name-to-dimension maps. A dimension is a number followed by px, em, or rem.
rounded:
none: 0px
sm: 4px
md: 8px
lg: 16px
xl: 24px
full: 9999px
spacing:
sm: 8px
md: 16px
lg: 32px
Spec-recommended rounded names: none, sm, md, lg, xl, full.
Components (components)#
Component tokens bind a UI component to values from the tiers above. Each component entry is a named object whose properties can be literal values or token references.
Component sub-token properties recognized by the spec:
Variant states (hover, active, pressed, disabled, focus, selected, checked) are expressed as separate keys suffixed to the base component name, e.g. button-primary-hover.
The reference syntax#
The {path.to.token} syntax is how DESIGN.md wires tier 3 back to tier 2 (and tier 2 back to tier 1). The path is dot-separated and starts with the frontmatter key:
| Reference | Resolves to |
|---|---|
{colors.tertiary} | The hex value of the tertiary color token |
{typography.label-md} | The full typography object for label-md |
{rounded.md} | The dimension value of the md rounded step |
The linter resolves every reference at lint time. In a component, a path that does not match a defined key is a broken-ref error (severity: error, file rejected). The parser supports up to 10 levels of reference depth and 20 levels of nesting. Cycles beyond those limits are also flagged as broken.
How tokens flow out#
To Tailwind v4#
The css-tailwind export target maps the color, typography, rounded, and spacing tokens to a Tailwind v4 @theme CSS block (component tokens are not exported). One command:
npx @google/design.md export DESIGN.md --format css-tailwind > tokens.css
Token sections map to CSS variable families:
| DESIGN.md section | CSS variable prefix |
|---|---|
colors | --color- |
typography.fontFamily | --font- |
typography.fontSize | --text- |
typography.lineHeight | --leading- (dimension values; a unitless multiplier is skipped) |
typography.letterSpacing | --tracking- |
typography.fontWeight | --font-weight- |
rounded | --radius- |
spacing | --spacing- |
Paste the @theme block into your globals.css alongside @import "tailwindcss" and the token names become utility class suffixes immediately. Step-by-step walkthrough: DESIGN.md to Tailwind v4 Theme.
To plain CSS custom properties#
New in 0.4.0, the css-vars export target writes a :root block of CSS custom properties that works without Tailwind:
npx @google/design.md export DESIGN.md --format css-vars > tokens.css
It emits colors, spacing, and rounded tokens only; typography and component tokens are not included, and unitless spacing values are skipped. Colors are written as lowercase hex. Real 0.4.0 output for a file with three colors (primary, tertiary, neutral), two spacing steps, and two rounded steps:
:root {
--color-primary: #1a1c1e;
--color-tertiary: #b8422e;
--color-neutral: #f7f5f2;
--spacing-sm: 8px;
--spacing-md: 16px;
--rounded-sm: 4px;
--rounded-md: 8px;
}
The optional --prefix flag namespaces every variable: --prefix ds turns --color-primary into --ds-color-primary. The flag applies to css-vars only.
To DTCG#
The dtcg export target emits a W3C Design Tokens Community Group JSON file:
npx @google/design.md export DESIGN.md --format dtcg > tokens.json
The output uses $schema: https://www.designtokens.org/schemas/2025.10/format.json, groups tokens by type, and expresses color values as sRGB component arrays with a hex convenience field. DESIGN.md can be your source of truth for human and agent use while still feeding DTCG-based tool pipelines. When to use each format: DESIGN.md vs DTCG.
All export formats#
The export command in 0.4.0 accepts five --format values:
| Format flag | Output |
|---|---|
css-tailwind | Tailwind v4 @theme block |
json-tailwind | Tailwind v3 theme.extend JSON |
tailwind | Alias for json-tailwind |
dtcg | W3C DTCG JSON |
css-vars | CSS custom properties in a :root block (colors, spacing, rounded), with an optional --prefix; new in 0.4.0 |
Since 0.4.0, a successful export always exits with code 0, even when the source file has lint errors, so an export step alone does not catch them. Use lint, not export, as the gate in CI.
Reference integrity: what the linter checks#
| Rule | Severity | What it catches |
|---|---|---|
broken-ref | error | A {reference} path that resolves to no defined token |
missing-primary | warning | Colors defined but no primary key present |
missing-typography | warning | Colors defined but typography is empty |
contrast-ratio | warning | Component backgroundColor/textColor pair below WCAG AA 4.5:1 |
orphaned-tokens | warning | A color token defined but never referenced by any component |
section-order | warning | Markdown sections appear out of canonical order |
token-like-ignored | warning | An unknown top-level key (such as palette:) holds token-like values that every export would drop; new in 0.4.0 |
Where to go next#
Spec section references (dive into a specific token type)
- Colors: color formats, reference syntax, WCAG AA contrast lint, orphaned-token rule
- Typography: all seven sub-fields, variable font support, linter rules
Learn articles (deeper explanation of the concepts above)
- AI Coding Agents and DESIGN.md: a minimal, lint-clean file that uses all three tiers
- DESIGN.md to Tailwind v4 Theme: step-by-step export and integration guide
- DESIGN.md vs DTCG: when to use each format and how the CLI bridges them
Was this page helpful?