How to Export DESIGN.md Tokens to Tailwind v4 CSS Format
Use the design.md export --format css-tailwind command to convert DESIGN.md files into a Tailwind v4-compatible @theme CSS block, or programmatically invoke TailwindV4EmitterHandler and serializeToCss from the @google/design.md package.
The google-labs-code/design.md repository provides a CLI tool that transforms design system documentation into executable code. By leveraging the export functionality, you can parse DESIGN.md files and emit standards-compliant CSS that Tailwind v4 consumes directly through its @theme directive.
Prerequisites and Installation
The CLI requires Node.js version 20 or higher, or alternatively Bun. Install the package globally via npm to access the design.md binary.
npm install -g @google/design.md
Exporting Tokens via the CLI
The design.md CLI supports multiple output formats. For Tailwind v4, specify the css-tailwind format, which generates a CSS @theme block containing CSS variables derived from your design tokens.
design.md export path/to/DESIGN.md --format css-tailwind > tailwind-theme.css
- Pass
-instead of a file path to read from STDIN. - The command exits with a non-zero status if token validation fails.
- Output prints to stdout for easy redirection into your build pipeline.
Programmatic Export with Node.js
For CI pipelines or custom build tools, import the linter and Tailwind v4 emitter directly from the package. This approach uses pure functions that perform no I/O, making them safe for automated environments.
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 & 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);
How the Export Pipeline Works
The export process operates in three distinct stages, each handled by specific modules in the packages/cli/src directory.
Stage 1: Parsing and Linting
In packages/cli/src/commands/export.ts, the CLI calls readInput to ingest the source file and lint to construct a DesignSystemState object. This state represents the validated token set, including categories like colors, typography, border-radius, and spacing.
Stage 2: Tailwind v4 Emitter
The TailwindV4EmitterHandler class in packages/cli/src/linter/tailwind/v4/handler.ts validates every token name against the CSS identifier regex /^[a-zA-Z0-9][a-zA-Z0-9-]*$/. It then maps the design system maps into a plain TailwindV4ThemeData object. If validation fails, the handler returns an error result that prevents invalid CSS identifiers from reaching the output.
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. This serialization is deterministic and produces the final CSS string that the CLI prints to stdout.
Integrating with Tailwind v4
Consume the generated CSS in your Tailwind configuration by reading the file and injecting it into the base styles.
// tailwind.config.js
const fs = require('fs');
const path = require('path');
module.exports = {
// ...your existing config
theme: {
// Tailwind v4 automatically reads `@theme` blocks from imported CSS.
},
plugins: [
// Load the generated @theme block so Tailwind can resolve the variables.
function ({ addBase }) {
const css = fs.readFileSync(path.resolve(__dirname, 'tailwind-theme.css'), 'utf8');
addBase(css);
},
],
};
Summary
- The
design.mdCLI exports DESIGN.md tokens to Tailwind v4 via thecss-tailwindformat. - The pipeline uses three stages: parsing/linting (
readInput,lint), emitting (TailwindV4EmitterHandler), and serialization (serializeToCss). - Token names must validate against the regex
/^[a-zA-Z0-9][a-zA-Z0-9-]*$/to ensure valid CSS identifiers. - Pure functional architecture makes the export pipeline deterministic and safe for CI environments.
Frequently Asked Questions
What Node.js version is required to run the design.md CLI?
The CLI requires Node.js version 20 or higher, or alternatively Bun. Earlier versions are not supported due to modern JavaScript dependencies used in the google-labs-code/design.md toolchain.
How does the Tailwind v4 emitter validate token names?
The TailwindV4EmitterHandler validates every token name against the CSS identifier regex /^[a-zA-Z0-9][a-zA-Z0-9-]*$/. If any token contains characters outside this pattern—such as spaces or special symbols—the export fails with a non-zero exit status and a descriptive error message.
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 reads the input from STDIN, allowing you to pipe design tokens directly into the CLI from other tools or scripts.
Is the export pipeline safe to run in CI environments?
Yes. Both the TailwindV4EmitterHandler and serializeToCss functions are pure and deterministic, performing no side effects or I/O operations. This makes the entire export pipeline safe for CI pipelines and automated build processes.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →