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"
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:

Sub-fieldTypeNotes
fontFamilystringCSS font-family name
fontSizeDimensione.g. 16px, 1.5rem
fontWeightnumbere.g. 400, 700
lineHeightDimension or numberunitless multiplier or dimension
letterSpacingDimensione.g. "-0.02em"
fontFeaturestringCSS font-feature-settings value
fontVariationstringCSS font-variation-settings value

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:

PropertyType
backgroundColorColor
textColorColor
typographyTypography reference
roundedDimension
paddingDimension
sizeDimension
heightDimension
widthDimension

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:

ReferenceResolves 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 sectionCSS 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 flagOutput
css-tailwindTailwind v4 @theme block
json-tailwindTailwind v3 theme.extend JSON
tailwindAlias for json-tailwind
dtcgW3C DTCG JSON
css-varsCSS 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#

RuleSeverityWhat it catches
broken-referrorA {reference} path that resolves to no defined token
missing-primarywarningColors defined but no primary key present
missing-typographywarningColors defined but typography is empty
contrast-ratiowarningComponent backgroundColor/textColor pair below WCAG AA 4.5:1
orphaned-tokenswarningA color token defined but never referenced by any component
section-orderwarningMarkdown sections appear out of canonical order
token-like-ignoredwarningAn 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)

Try it in the tool

Was this page helpful?