How to Export DESIGN.md Tokens to Tailwind v4 CSS

The @google/design.md CLI exports DESIGN.md tokens to Tailwind v4's @theme format using the --format css-tailwind flag, generating a CSS file that maps design tokens to CSS variables inside an @theme block.

The google-labs-code/design.md repository provides a toolchain for managing design tokens in markdown. When targeting Tailwind v4, you can export DESIGN.md tokens to the CSS @theme format, which Tailwind v4 consumes natively to configure theme variables.

How the Export Pipeline Works

The export process follows a deterministic three-stage pipeline implemented in packages/cli/src/commands/export.ts:

Stage 1: Parsing and Linting

The readInput function ingests the source file, and the lint function constructs a DesignSystemState object that represents the validated token set.

Stage 2: Tailwind v4 Emission

The TailwindV4EmitterHandler class in packages/cli/src/linter/tailwind/v4/handler.ts validates every token name against CSS identifier rules using the regex /^[a-zA-Z0-9][a-zA-Z0-9-]*$/. It then maps the design system categories—colors, typography, border-radius, and spacing—into a plain TailwindV4ThemeData object.

Stage 3: CSS Serialization

The serializeToCss function in packages/cli/src/linter/tailwind/v4/serialize.ts walks the ordered CATEGORIES list and writes each entry as a CSS variable inside an @theme block. Because both the emitter and serializer are pure functions with no I/O side effects, the pipeline is deterministic and safe for CI environments.

Installation Requirements

Install the CLI globally using npm or Bun. The tool requires Node.js ≥ 20 or Bun.

npm install -g @google/design.md

# or

bun add @google/design.md

CLI Export Method

Run the export command with the --format css-tailwind flag to generate the CSS output. You can redirect the stdout to a file or pipe it to another process.

design.md export path/to/DESIGN.md --format css-tailwind > tailwind-theme.css

The command accepts the following behaviors:

  • Use - as the file path to read from STDIN.
  • The command exits with a non-zero status if any token name fails validation (e.g., contains characters not allowed by /^[a-zA-Z0-9][a-zA-Z0-9-]*$/).

Programmatic Usage (Node.js)

For custom build pipelines, import the linter and Tailwind v4 emitter directly. This approach gives you programmatic access to the DesignSystemState and_validation errors.

import { readFile } from 'fs/promises';
import { lint } from '@google/design.md/linter';
import { TailwindV4EmitterHandler } from '@google/design.md/linter/tailwind/v4/handler';
import { serializeToCss } from '@google/design.md/linter/tailwind/v4/serialize';

// 1. Load DESIGN.md text
const designMd = await readFile('./examples/totality-festival/DESIGN.md', 'utf8');

// 2. Lint to get the design-system model
const report = lint(designMd);

// 3. Emit Tailwind v4 theme data
const emitter = new TailwindV4EmitterHandler();
const result = emitter.execute(report.designSystem);

if (!result.success) {
  throw new Error(result.error.message);
}

// 4. Serialize to CSS @theme block
const css = serializeToCss(result.data.theme);
console.log(css);

Integrating with Tailwind v4

Import the generated CSS file into your Tailwind configuration so that the @theme block is available to the Tailwind engine.

// tailwind.config.js
const fs = require('fs');
const path = require('path');

module.exports = {
  plugins: [
    function ({ addBase }) {
      const css = fs.readFileSync(path.resolve(__dirname, 'tailwind-theme.css'), 'utf8');
      addBase(css);
    },
  ],
};

Tailwind v4 automatically reads @theme blocks from imported CSS, resolving the CSS custom properties as theme variables.

Summary

  • The css-tailwind format produces a native Tailwind v4 @theme CSS block.
  • The pipeline runs through readInput → lint → TailwindV4EmitterHandler → serializeToCss.
  • Token names must match the regex /^[a-zA-Z0-9][a-zA-Z0-9-]*$/ or the export will fail with a non-zero exit code.
  • The emitter and serializer are pure functions, making the export safe for CI pipelines.

Frequently Asked Questions

What Node.js version is required to run the exporter?

The CLI requires Node.js ≥ 20 or Bun. Earlier Node versions are not supported due to modern JavaScript features used in the google-labs-code/design.md toolchain.

Can I read the DESIGN.md file from STDIN instead of a file path?

Yes. Pass - as the file path argument to the export command: design.md export - --format css-tailwind. This allows you to pipe content from other tools or use the CLI in shell pipelines.

What happens if my DESIGN.md contains invalid token names?

The export will fail with a non-zero exit status. The TailwindV4EmitterHandler validates every token name against the CSS identifier regex /^[a-zA-Z0-9][a-zA-Z0-9-]*$/, and any mismatch will raise a validation error before serialization occurs.

Where is the Tailwind v4 emitter logic implemented?

The core logic resides in two files within the @google/design.md package: packages/cli/src/linter/tailwind/v4/handler.ts contains the TailwindV4EmitterHandler class that transforms the design system state, and packages/cli/src/linter/tailwind/v4/serialize.ts contains the serializeToCss function that generates the final CSS output.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →