DESIGN.md to Tailwind v4 Theme

Learn about Design Tokens: The Complete Guide
On this page

The @google/design.md CLI ships a css-tailwind export target that emits a Tailwind v4 @theme block with CSS custom properties for every token in your DESIGN.md file. Paste the block into your globals.css, add @import "tailwindcss", and every --color-*, --spacing-*, and --radius-* variable becomes a Tailwind utility immediately.

Background: Tailwind v4 and the @theme model#

Tailwind v4 moved away from the JavaScript tailwind.config.js theme object and adopted a CSS-first configuration model. Themes are now defined directly in CSS using a special @theme rule:

@import "tailwindcss";

@theme {
  --color-primary: #0F172A;
  --color-secondary: #475569;
  --color-tertiary: #3B82F6;
  --spacing-sm: 8px;
  --spacing-md: 16px;
  --radius-md: 8px;
}

Any CSS custom property defined inside @theme is registered with Tailwind's engine. The prefix determines the utility family: --color-* produces bg-*, text-*, border-*, and so on; --spacing-* feeds the spacing scale; --radius-* feeds rounded-*.

This is the model used by this site. The app/globals.css file defines @theme inline { --color-canvas: var(--canvas); ... } to expose the chrome palette to Tailwind utilities without duplicating the values.

The css-tailwind export target#

The @google/design.md CLI has four export formats. The one you want for Tailwind v4 is css-tailwind:

FormatWhat it emits
css-tailwindTailwind v4 @theme block with CSS custom properties
json-tailwindTailwind v3 theme.extend JSON object
tailwindAlias for json-tailwind
dtcgW3C Design Tokens Community Group JSON

The css-tailwind target maps each DESIGN.md token section to a CSS variable family:

DESIGN.md sectionCSS variable prefix
colors--color-
typography.fontFamily--font-
typography.fontSize--text-
typography.lineHeight--leading-
typography.letterSpacing--tracking-
typography.fontWeight--font-weight-
rounded--radius-
spacing--spacing-

Step 1: Write or lint your DESIGN.md#

Start from a valid DESIGN.md. If you do not have one yet, use the tool to build one interactively. To validate an existing file:

npx @google/design.md lint DESIGN.md

Exit code 0 means no errors (warnings are acceptable). If you see a broken-ref error, fix the unresolved reference before exporting. The orphaned-tokens rule fires only when your file includes a non-empty components section; without components it is skipped entirely.

A minimal DESIGN.md that covers all exported sections:

---
name: Slate UI
version: alpha
colors:
  primary:    "#0F172A"
  secondary:  "#475569"
  tertiary:   "#3B82F6"
  neutral:    "#F8FAFC"
  surface:    "#FFFFFF"
  on-surface: "#0F172A"
  error:      "#EF4444"
typography:
  headline-lg:
    fontFamily: "Inter"
    fontSize: 36px
    fontWeight: 700
    lineHeight: "1.1"
    letterSpacing: "-0.02em"
  body-md:
    fontFamily: "Inter"
    fontSize: 16px
    fontWeight: 400
    lineHeight: "1.65"
rounded:
  sm: 4px
  md: 8px
  lg: 16px
spacing:
  sm: 8px
  md: 16px
  lg: 32px
---

Note: lineHeight must be a quoted string (e.g. "1.1") for the parser to retain it. An unquoted YAML number (e.g. 1.1) is dropped and no --leading-* variable is emitted.

Step 2: Run the export#

npx @google/design.md export DESIGN.md --format css-tailwind

The CLI writes the @theme block to stdout. Redirect it to a file if you want to keep it separate:

npx @google/design.md export DESIGN.md --format css-tailwind > tokens.css

For the DESIGN.md above, the output looks like this:

@theme {
  --color-primary: #0f172a;
  --color-secondary: #475569;
  --color-tertiary: #3b82f6;
  --color-neutral: #f8fafc;
  --color-surface: #ffffff;
  --color-on-surface: #0f172a;
  --color-error: #ef4444;
  --font-headline-lg: "Inter";
  --font-body-md: "Inter";
  --text-headline-lg: 36px;
  --text-body-md: 16px;
  --leading-headline-lg: 1.1;
  --leading-body-md: 1.65;
  --tracking-headline-lg: -0.02em;
  --font-weight-headline-lg: 700;
  --font-weight-body-md: 400;
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 16px;
  --spacing-sm: 8px;
  --spacing-md: 16px;
  --spacing-lg: 32px;
}

Step 3: Add the block to your globals.css#

In a Tailwind v4 project, globals.css (or whichever file holds your @import "tailwindcss" statement) is where the @theme block lives. You have two options:

Option A: Paste directly into globals.css#

@import "tailwindcss";

@theme {
  --color-primary: #0F172A;
  --color-secondary: #475569;
  --color-tertiary: #3B82F6;
  --color-neutral: #F8FAFC;
  --color-surface: #FFFFFF;
  --color-on-surface: #0F172A;
  --color-error: #EF4444;
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 16px;
  --spacing-sm: 8px;
  --spacing-md: 16px;
  --spacing-lg: 32px;
}

Option B: Keep tokens in a separate file and import it#

/* globals.css */
@import "tailwindcss";
@import "./tokens.css";
/* tokens.css  (the css-tailwind export output) */
@theme {
  --color-primary: #0F172A;
  /* ... */
}

Both options work. Option B is easier to regenerate when the DESIGN.md changes.

Step 4: Use the tokens as Tailwind utilities#

Once the @theme block is in place, every registered variable becomes a utility class. Because Tailwind v4 derives utilities from the CSS variable names, you get the full utility set without any additional configuration:

<!-- color utilities -->
<h1 class="text-primary">Headline</h1>
<div class="bg-surface text-on-surface">Card content</div>
<button class="bg-tertiary text-white">Primary action</button>
<p class="text-error">Something went wrong.</p>

<!-- spacing and radius utilities -->
<div class="p-md rounded-lg">Padded card with large radius</div>
<section class="mt-lg">Spaced section</section>

The token names from DESIGN.md become the utility suffixes directly. --color-tertiary becomes bg-tertiary, text-tertiary, and border-tertiary. --radius-md becomes rounded-md.

Step 5: Re-export when your DESIGN.md changes#

Tokens and the Tailwind theme are now kept in sync through the CLI command. Set up a script in package.json to make regeneration one command:

{
  "scripts": {
    "tokens": "design.md export DESIGN.md --format css-tailwind > src/tokens.css"
  }
}

Or if you use npx directly:

npx @google/design.md export DESIGN.md --format css-tailwind > src/tokens.css

The @theme inline variant#

Tailwind v4 also accepts @theme inline, which resolves the variables eagerly at build time rather than leaving them as runtime CSS variables. This is useful when you want to reference a :root custom property inside @theme rather than duplicating the value:

:root {
  --brand-blue: #3B82F6;
}

@theme inline {
  --color-tertiary: var(--brand-blue);
}

The css-tailwind export omits the inline keyword because it writes literal values, not references to other properties. If you want the inline variant (for example, to combine with a dark-mode :root block), add inline manually after pasting the output.

Up to the guide#

Try it in the tool