How to Export DESIGN.md Tokens to W3C DTCG Format

Design tokens defined in a DESIGN.md file can be exported to W3C-compliant DTCG JSON using the npx @google/design.md export --format dtcg CLI command or programmatically via the DtcgEmitterHandler class.

The google-labs-code/design.md repository provides a complete toolchain for converting design documentation into standardized token formats. When you need to export DESIGN.md tokens to W3C DTCG format, the project offers both a streamlined CLI interface and a flexible TypeScript API that maps internal token states to the official Design Tokens Community Group specification.

CLI Export Method

The fastest way to generate a tokens.json file is through the CLI command defined in packages/cli/src/commands/export.ts.

Syntax and Usage

Run the export command from your project root, specifying the DTCG format and the path to your DESIGN.md file:

npx @google/design.md export --format dtcg DESIGN.md > tokens.json

This command parses your DESIGN.md input, validates the syntax through the linter, and delegates to the DTCG emitter based on the --format flag.

How the CLI Processes DTCG Export

In export.ts, the command instantiates new DtcgEmitterHandler() when --format dtcg is specified. The handler receives the validated DesignSystemState and returns a JSON object conforming to the 2025.10 DTCG schema. The CLI then prints the result with 2-space indentation using JSON.stringify(result.data, null, 2).

Programmatic Export with Node.js

When integrating token export into build pipelines or custom tools, import the DtcgEmitterHandler directly from @google/design.md/linter/dtcg.

Implementation Steps

The following TypeScript implementation demonstrates how to lint a DESIGN.md file and convert the resulting state to DTCG format:

import { readFileSync } from 'fs';
import { lint } from '@google/design.md/linter';
import { DtcgEmitterHandler } from '@google/design.md/linter/dtcg';

// 1. Load a DESIGN.md file
const markdown = readFileSync('DESIGN.md', 'utf8');

// 2. Run the linter to obtain a DesignSystemState
const report = lint(markdown);

// 3. Convert to DTCG tokens
const handler = new DtcgEmitterHandler();
const result = handler.execute(report.designSystem);

if (result.success) {
  // 4. Write out the tokens.json file
  const json = JSON.stringify(result.data, null, 2);
  console.log(json);
} else {
  console.error('Export failed:', result.error);
}

The execute() method in packages/cli/src/linter/dtcg/handler.ts returns { success: true, data: <tokens> } when the conversion succeeds.

DTCG Output Structure and Schema

The emitter generates JSON that validates against https://www.designtokens.org/schemas/2025.10/format.json.

Token Groups and Mappings

The DtcgEmitterHandler.execute() method organizes tokens into logical groups:

  • Colors → color group via mapColors, converting values to sRGB arrays and hex strings using colorToValue
  • Spacing and Rounded → spacing and rounded groups via mapDimensionGroup, outputting {value, unit} objects through dimToValue
  • Typography → typography group via mapTypography, transforming properties into DTCG-structured objects using typographyToValue

Each group includes the $type property and optional $description metadata from the DESIGN.md source.

Expected JSON Format

The resulting file follows the W3C DTCG specification with typed token groups:

{
  "$schema": "https://www.designtokens.org/schemas/2025.10/format.json",
  "$description": "Heritage design system",
  "color": {
    "$type": "color",
    "primary": {
      "$value": {
        "colorSpace": "srgb",
        "components": [0.102, 0.110, 0.118],
        "hex": "#1a1c1e"
      }
    },
    "tertiary": {
      "$value": {
        "colorSpace": "srgb",
        "components": [0.724, 0.259, 0.180],
        "hex": "#b8422e"
      }
    }
  },
  "spacing": {
    "$type": "dimension",
    "sm": { "$value": { "value": 8, "unit": "px" } },
    "md": { "$value": { "value": 16, "unit": "px" } }
  },
  "typography": {
    "h1": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Public Sans",
        "fontSize": { "value": 3, "unit": "rem" }
      }
    }
  }
}

Core Implementation Details

DtcgEmitterHandler Architecture

Located in packages/cli/src/linter/dtcg/handler.ts, the DtcgEmitterHandler implements the DtcgEmitterSpec interface defined in packages/cli/src/linter/dtcg/spec.ts. Its execute(state) method constructs the token hierarchy by traversing the DesignSystemState and applying type-specific conversion logic.

Value Conversion Logic

Internal conversion utilities ensure specification compliance:

  • colorToValue: Transforms color tokens into sRGB component arrays with hex equivalents
  • dimToValue: Converts dimensional tokens (spacing, rounded corners) to objects with numeric values and CSS units
  • typographyToValue: Structures font families, sizes, and weights according to DTCG typography token specifications

Summary

  • Use npx @google/design.md export --format dtcg DESIGN.md for quick CLI exports to tokens.json
  • Import DtcgEmitterHandler from @google/design.md/linter/dtcg for programmatic export in Node.js/TypeScript applications
  • The handler maps DesignSystemState to the W3C DTCG 2025.10 schema, organizing tokens into color, spacing, rounded, and typography groups
  • Value conversions automatically handle sRGB color spaces, dimension units, and typography structures
  • Source files: packages/cli/src/commands/export.ts (CLI entry) and packages/cli/src/linter/dtcg/handler.ts (emitter logic)

Frequently Asked Questions

What is the W3C DTCG format?

The W3C Design Tokens Community Group (DTCG) format is a standardized JSON schema for sharing design tokens across tools and platforms. It uses specific properties like $value, $type, and $description to define colors, dimensions, and typography in a tool-agnostic way, enabling interoperability between design and development workflows.

Can I export only specific token groups to DTCG?

Currently, the DtcgEmitterHandler exports all valid token groups (colors, spacing, rounded, typography) defined in your DESIGN.md. To filter specific groups, you would need to manipulate the DesignSystemState object before passing it to handler.execute() or post-process the resulting JSON to remove unwanted categories.

Does the CLI support watching DESIGN.md files for changes?

The standard export command in packages/cli/src/commands/export.ts runs as a one-time operation. For continuous export during development, you would need to wrap the CLI command in a file watcher like chokidar-cli or use the programmatic API within a custom watch script that monitors file modifications.

Which DTCG schema version does design.md support?

As implemented in packages/cli/src/linter/dtcg/handler.ts, the emitter outputs JSON conforming to the 2025.10 DTCG schema, referenced via "$schema": "https://www.designtokens.org/schemas/2025.10/format.json" in the generated 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 →