How to Export DESIGN.md Tokens to Tailwind v3 JSON Format: A Complete Guide
The google-labs-code/design.md CLI converts DESIGN.md tokens into Tailwind v3-compatible JSON using the json-tailwind format option, which wraps the token mappings in a { "theme": { "extend": ... } } structure for direct import into your tailwind.config.js.
The google-labs-code/design.md repository ships with a command-line tool that parses DESIGN.md files and validates their design tokens. When you need to export DESIGN.md tokens to Tailwind v3 JSON format, the CLI exposes a dedicated emitter that transforms the parsed design system state into a configuration object matching Tailwind's theme.extend schema.
How the Export Pipeline Works
The export process follows a strict three-stage pipeline implemented in the CLI source code:
-
Input Reading – The
readInpututility inpackages/cli/src/utils.tsaccepts either a file path or stdin (-) and returns the raw content string. -
Linting and Parsing – The
lint(content)function processes the raw markdown, validates token definitions, and constructs aDesignSystemStateobject containing normalized groups for colors, typography, spacing, rounded corners, and other design primitives. -
Tailwind Emission – When the format argument is
json-tailwind(or its aliastailwind), the command instantiates aTailwindEmitterHandlerfrompackages/cli/src/linter/tailwind/handler.ts. The handler'sexecute(state)method maps each token group to its corresponding Tailwind configuration key:colors→ color tokensfontFamilyandfontSize→ typography definitionsborderRadius→ rounded tokensspacing→ spacing units
The TailwindEmitterHandler.execute(state) function is a pure function with no side effects, meaning it returns a deterministic JSON object without modifying the input state or filesystem. The result is wrapped in { "theme": { "extend": ... } } and serialized using JSON.stringify(result.data, null, 2) for pretty-printed output.
CLI Command Syntax
Invoke the export command from the repository root using the CLI entry point defined in packages/cli/src/index.js:
# Using pnpm (recommended)
pnpm run cli export path/to/DESIGN.md json-tailwind > tailwind.tokens.json
# Using Node directly
node packages/cli/src/index.js export ./examples/totality-festival/DESIGN.md tailwind > tailwind.tokens.json
The command accepts two aliases for the format argument:
json-tailwind(explicit)tailwind(shorthand)
If you provide an invalid format, the CLI exits with code 1 and writes a JSON error object to stderr (see export.ts lines 44-48).
For stdin input, pass - as the file path:
cat DESIGN.md | node packages/cli/src/index.js export - json-tailwind
Understanding the Tailwind v3 JSON Output Structure
The emitted JSON structure follows Tailwind v3's configuration schema exactly. Given a DESIGN.md file with this content:
---
name: Example System
colors:
primary: "#ff6f61"
secondary: "#4a90e2"
typography:
body:
fontFamily: Inter
fontSize: 16px
lineHeight: 24px
fontWeight: 400
rounded:
sm: 4px
spacing:
unit: 8px
---
The exporter generates:
{
"theme": {
"extend": {
"colors": {
"primary": "#ff6f61",
"secondary": "#4a90e2"
},
"fontFamily": {
"body": ["Inter"]
},
"fontSize": {
"body": ["16px", { "lineHeight": "24px", "fontWeight": "400" }]
},
"borderRadius": {
"sm": "4px"
},
"spacing": {
"unit": "8px"
}
}
}
}
This structure allows Tailwind to generate utility classes like text-primary, bg-secondary, font-body, rounded-sm, and mt-unit based on your DESIGN.md definitions.
Integrating with tailwind.config.js
Because the output is valid JSON wrapped in a theme.extend object, you can require it directly into your Tailwind configuration:
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: "class",
theme: {
extend: require("./tailwind.tokens.json").theme.extend,
},
};
After running your build command (e.g., npm run dev), the following utility classes become available:
text-primarymaps to#ff6f61bg-secondarymaps to#4a90e2font-bodyapplies the Inter font familyrounded-smapplies4pxborder radiusmt-unitapplies8pxmargin-top
Key Source Files and Implementation Details
Understanding the underlying implementation helps when debugging or extending the export functionality:
-
packages/cli/src/commands/export.ts– The CLI entry point that validates arguments, selects the appropriate emitter handler, and prints the formatted result to stdout. -
packages/cli/src/linter/tailwind/handler.ts– Contains theTailwindEmitterHandlerclass and itsexecute(state)method, which performs the actual mapping fromDesignSystemStateto Tailwind configuration keys. -
packages/cli/src/utils.ts– Provides thereadInputhelper that abstracts file system and stdin reading, enabling the export command to work with both physical files and piped input. -
examples/totality-festival/tailwind.config.js– A working example in the repository demonstrating how to consume the emitted JSON in a real Tailwind v3 project.
Summary
- The google-labs-code/design.md CLI provides native support for exporting to Tailwind v3 via the
json-tailwindformat argument. - The export pipeline uses
TailwindEmitterHandler.execute(state)inpackages/cli/src/linter/tailwind/handler.tsto convert parsed tokens into atheme.extendcompatible structure. - Output is wrapped in
{ "theme": { "extend": ... } }and pretty-printed with 2-space indentation for direct consumption bytailwind.config.js. - The handler supports colors, typography (fontFamily, fontSize), borderRadius, and spacing tokens.
- Because the emitter is a pure function, you can safely redirect stdout to a file or pipe it to other tools without side effects.
Frequently Asked Questions
What Tailwind theme keys are supported when exporting DESIGN.md tokens?
The TailwindEmitterHandler maps four primary token categories to Tailwind configuration keys: colors for color tokens, fontFamily and fontSize for typography definitions, borderRadius for rounded tokens, and spacing for spacing units. Complex typography tokens automatically generate the tuple format required by Tailwind v3's fontSize configuration, including line-height and font-weight metadata.
Can I use stdin instead of a file path for the export command?
Yes. The readInput utility in packages/cli/src/utils.ts supports stdin input when you pass - as the file argument. This allows you to pipe DESIGN.md content directly into the CLI: cat DESIGN.md | node packages/cli/src/index.js export - json-tailwind.
Does the CLI validate the DESIGN.md file before exporting?
Yes. The export command internally calls lint(content) to validate the DESIGN.md structure and build a DesignSystemState object. If validation fails, the CLI exits with code 1 and prints error details to stderr, preventing the generation of invalid Tailwind JSON.
Is there a difference between the json-tailwind and tailwind format arguments?
No. According to the source in packages/cli/src/commands/export.ts, tailwind is simply an alias for json-tailwind. Both arguments instantiate the same TailwindEmitterHandler and produce identical JSON output wrapped in the theme.extend structure.
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 →