DESIGN.md
A format specification for describing a visual identity to coding agents — pre-populated with all 62 components from this catalog.
What is DESIGN.md?
A DESIGN.md file gives an AI agent a persistent, structured understanding of your design system. It combines machine-readable design tokens (YAML front matter) with human-readable design rationale (markdown prose). Tokens give agents exact values. Prose tells them why those values exist and how to apply them.
The format was introduced by Google as an open spec. The CLI lives at @google/design.md and validates a file against the schema, checks WCAG contrast on component pairs, and detects regressions between versions.
The format at a glance
A DESIGN.md file has two layers: YAML front matter (the normative token values) and a markdown body (the rationale). Sections in the body use ## headings and appear in a canonical order: Overview, Colors, Typography, Layout, Elevation, Shapes, Components, Do's and Don'ts.
Recommended DESIGN.md template
The template below is a starting point — placeholder tokens for colors, typography, rounding, and spacing, plus a pre-populated components: block with all 62 components organized by category. Drop it into a DESIGN.md file at the root of your project, replace the placeholder values with your brand tokens, and hand it to any agent that supports the format.
---
version: alpha
name: Your Design System
description: >
One or two sentences describing the brand and the feel of the UI.
Mention the overall mood (e.g. minimalist, editorial, playful), the
hierarchy of contrast, and how the accent color is used.
colors:
bg: "#FFFFFF" # page background
bg-sidebar: "#F7F7F7" # secondary surface (nav, sidebar)
bg-card: "#F2F2F2" # raised surface (cards, popovers)
bg-input: "#F4F4F5" # form-control surface
bg-hover: "#EAEAEA" # interactive hover state
border: "#D4D4D8" # dividers and outlines
text: "#18181B" # primary body text
text-muted: "#52525B" # secondary text, captions
text-subtle: "#A1A1AA" # tertiary text, placeholders
accent: "#0F62FE" # interactive / brand color
primary: "{colors.accent}"
typography:
display:
fontFamily: Inter
fontSize: 3rem
fontWeight: 700
lineHeight: 1.1
h1:
fontFamily: Inter
fontSize: 2rem
fontWeight: 700
lineHeight: 1.2
h2:
fontFamily: Inter
fontSize: 1.375rem
fontWeight: 600
lineHeight: 1.3
h3:
fontFamily: Inter
fontSize: 1.0625rem
fontWeight: 600
lineHeight: 1.4
body-md:
fontFamily: Inter
fontSize: 1rem
fontWeight: 400
lineHeight: 1.6
body-sm:
fontFamily: Inter
fontSize: 0.875rem
fontWeight: 400
lineHeight: 1.5
button:
fontFamily: Inter
fontSize: 0.875rem
fontWeight: 600
lineHeight: 1
letterSpacing: 0.01em
label-caps:
fontFamily: Inter
fontSize: 0.75rem
fontWeight: 600
lineHeight: 1
letterSpacing: 0.04em
rounded:
sm: 4px
md: 8px
lg: 12px
pill: 9999px
spacing:
xs: 4px
sm: 8px
md: 16px
lg: 24px
xl: 40px
components:
# ── Action ──
button:
backgroundColor: "{colors.accent}"
textColor: "{colors.bg}"
typography: "{typography.button}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
button-hover:
backgroundColor: "{colors.text}"
textColor: "{colors.bg}"
toggle:
backgroundColor: "{colors.bg-hover}"
textColor: "{colors.text}"
typography: "{typography.button}"
rounded: "{rounded.md}"
padding: "{spacing.sm}"
toggle-active:
backgroundColor: "{colors.accent}"
textColor: "{colors.bg}"
toggle-group:
backgroundColor: "{colors.bg-hover}"
textColor: "{colors.text}"
typography: "{typography.button}"
rounded: "{rounded.md}"
padding: "{spacing.xs}"
toolbar:
backgroundColor: "{colors.bg-card}"
textColor: "{colors.text}"
typography: "{typography.body-sm}"
rounded: "{rounded.md}"
padding: "{spacing.sm}"
# ── Form ──
input:
backgroundColor: "{colors.bg-input}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
input-focus:
backgroundColor: "{colors.bg-input}"
textColor: "{colors.text}"
textarea:
backgroundColor: "{colors.bg-input}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
select:
backgroundColor: "{colors.bg-input}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
combobox:
backgroundColor: "{colors.bg-input}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
search:
backgroundColor: "{colors.bg-input}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.pill}"
padding: "{spacing.md}"
checkbox:
backgroundColor: "{colors.bg-input}"
textColor: "{colors.text}"
rounded: "{rounded.sm}"
size: 18px
radio-group:
backgroundColor: "{colors.bg-input}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.pill}"
switch:
backgroundColor: "{colors.bg-hover}"
textColor: "{colors.bg}"
rounded: "{rounded.pill}"
switch-on:
backgroundColor: "{colors.accent}"
slider:
backgroundColor: "{colors.bg-hover}"
textColor: "{colors.accent}"
rounded: "{rounded.pill}"
rating:
backgroundColor: "transparent"
textColor: "{colors.accent}"
typography: "{typography.body-md}"
label:
backgroundColor: "transparent"
textColor: "{colors.text-muted}"
typography: "{typography.label-caps}"
form:
backgroundColor: "transparent"
textColor: "{colors.text}"
typography: "{typography.body-md}"
padding: "{spacing.lg}"
file-upload:
backgroundColor: "{colors.bg-card}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.md}"
padding: "{spacing.lg}"
number-input:
backgroundColor: "{colors.bg-input}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
calendar:
backgroundColor: "{colors.bg-card}"
textColor: "{colors.text}"
typography: "{typography.body-sm}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
date-picker:
backgroundColor: "{colors.bg-input}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
time-picker:
backgroundColor: "{colors.bg-input}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
color-picker:
backgroundColor: "{colors.bg-input}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
# ── Navigation ──
link:
backgroundColor: "transparent"
textColor: "{colors.accent}"
typography: "{typography.body-md}"
breadcrumb:
backgroundColor: "transparent"
textColor: "{colors.text-muted}"
typography: "{typography.body-sm}"
padding: "{spacing.sm}"
tabs:
backgroundColor: "transparent"
textColor: "{colors.text-muted}"
typography: "{typography.button}"
padding: "{spacing.sm}"
tabs-active:
textColor: "{colors.text}"
pagination:
backgroundColor: "transparent"
textColor: "{colors.text}"
typography: "{typography.body-sm}"
rounded: "{rounded.sm}"
padding: "{spacing.sm}"
stepper:
backgroundColor: "transparent"
textColor: "{colors.text-muted}"
typography: "{typography.body-sm}"
rounded: "{rounded.pill}"
menubar:
backgroundColor: "{colors.bg-sidebar}"
textColor: "{colors.text}"
typography: "{typography.body-sm}"
rounded: "{rounded.sm}"
padding: "{spacing.sm}"
navigation-menu:
backgroundColor: "{colors.bg-sidebar}"
textColor: "{colors.text}"
typography: "{typography.body-sm}"
rounded: "{rounded.sm}"
padding: "{spacing.sm}"
dropdown-menu:
backgroundColor: "{colors.bg-card}"
textColor: "{colors.text}"
typography: "{typography.body-sm}"
rounded: "{rounded.md}"
padding: "{spacing.sm}"
context-menu:
backgroundColor: "{colors.bg-card}"
textColor: "{colors.text}"
typography: "{typography.body-sm}"
rounded: "{rounded.md}"
padding: "{spacing.sm}"
# ── Overlay ──
dialog:
backgroundColor: "{colors.bg}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.lg}"
padding: "{spacing.lg}"
alert-dialog:
backgroundColor: "{colors.bg}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.lg}"
padding: "{spacing.lg}"
sheet:
backgroundColor: "{colors.bg}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.lg}"
padding: "{spacing.lg}"
popover:
backgroundColor: "{colors.bg-card}"
textColor: "{colors.text}"
typography: "{typography.body-sm}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
hover-card:
backgroundColor: "{colors.bg-card}"
textColor: "{colors.text}"
typography: "{typography.body-sm}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
tooltip:
backgroundColor: "{colors.text}"
textColor: "{colors.bg}"
typography: "{typography.body-sm}"
rounded: "{rounded.sm}"
padding: "{spacing.sm}"
# ── Feedback ──
alert:
backgroundColor: "{colors.bg-card}"
textColor: "{colors.text}"
typography: "{typography.body-sm}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
banner:
backgroundColor: "{colors.bg-card}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.sm}"
padding: "{spacing.md}"
toast:
backgroundColor: "{colors.text}"
textColor: "{colors.bg}"
typography: "{typography.body-sm}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
progress:
backgroundColor: "{colors.bg-hover}"
textColor: "{colors.accent}"
rounded: "{rounded.pill}"
meter:
backgroundColor: "{colors.bg-hover}"
textColor: "{colors.accent}"
rounded: "{rounded.pill}"
spinner:
backgroundColor: "transparent"
textColor: "{colors.accent}"
size: 24px
skeleton:
backgroundColor: "{colors.bg-hover}"
textColor: "{colors.bg-hover}"
rounded: "{rounded.sm}"
empty-state:
backgroundColor: "transparent"
textColor: "{colors.text-muted}"
typography: "{typography.body-md}"
padding: "{spacing.xl}"
# ── Data Display ──
avatar:
backgroundColor: "{colors.bg-hover}"
textColor: "{colors.text}"
typography: "{typography.body-sm}"
rounded: "{rounded.pill}"
size: 32px
badge:
backgroundColor: "{colors.accent}"
textColor: "{colors.bg}"
typography: "{typography.label-caps}"
rounded: "{rounded.pill}"
padding: "{spacing.xs}"
tag:
backgroundColor: "{colors.bg-hover}"
textColor: "{colors.text-muted}"
typography: "{typography.label-caps}"
rounded: "{rounded.sm}"
padding: "{spacing.xs}"
chip:
backgroundColor: "{colors.bg-hover}"
textColor: "{colors.text}"
typography: "{typography.body-sm}"
rounded: "{rounded.pill}"
padding: "{spacing.sm}"
table:
backgroundColor: "{colors.bg}"
textColor: "{colors.text}"
typography: "{typography.body-sm}"
rounded: "{rounded.sm}"
data-table:
backgroundColor: "{colors.bg}"
textColor: "{colors.text}"
typography: "{typography.body-sm}"
rounded: "{rounded.sm}"
list:
backgroundColor: "transparent"
textColor: "{colors.text}"
typography: "{typography.body-md}"
padding: "{spacing.sm}"
tree-view:
backgroundColor: "transparent"
textColor: "{colors.text}"
typography: "{typography.body-sm}"
padding: "{spacing.sm}"
timeline:
backgroundColor: "transparent"
textColor: "{colors.text}"
typography: "{typography.body-sm}"
padding: "{spacing.md}"
# ── Disclosure ──
accordion:
backgroundColor: "{colors.bg-card}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
collapsible:
backgroundColor: "{colors.bg-card}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.md}"
padding: "{spacing.md}"
# ── Layout ──
card:
backgroundColor: "{colors.bg-card}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.md}"
padding: "{spacing.lg}"
scroll-area:
backgroundColor: "transparent"
textColor: "{colors.text}"
separator:
backgroundColor: "{colors.border}"
height: 1px
# ── Content ──
carousel:
backgroundColor: "{colors.bg}"
textColor: "{colors.text}"
typography: "{typography.body-md}"
rounded: "{rounded.md}"
image:
backgroundColor: "{colors.bg-card}"
rounded: "{rounded.md}"
icon:
backgroundColor: "transparent"
textColor: "{colors.text}"
size: 18px
---
## Overview
Describe the personality of the UI in two or three sentences. What mood
should the interface evoke? Where does attention land first? What is
deliberately restrained so that the accent (or the content) can lead?
## Colors
Explain the role of each color token, not just its value. Tokens are the
contract — prose tells agents when to reach for which.
- **Background:** The base surface. Should carry the longest reading
passages comfortably.
- **Card / Input / Hover:** Surface variants that signal grouping or
interactivity without needing borders.
- **Text / Muted / Subtle:** A three-step hierarchy for primary content,
secondary metadata, and tertiary hints like placeholders.
- **Accent:** Reserved for interaction (buttons, links, focus rings,
active states). The smaller its footprint, the louder its signal.
If you support multiple themes (light, dark, brand variants), each
overrides the same token names. Components reference tokens, never raw
hex values, so theming works without component changes.
## Typography
Pick one typeface and stay with it. Hierarchy comes from weight and size,
not family. Body text breathes (line-height ≥ 1.5); UI text (buttons,
labels) tightens (line-height ≈ 1) with slight letter-spacing for
clarity at small sizes.
If a second face is necessary (e.g. a serif for editorial display), name
it explicitly here and explain when it appears.
## Layout
- **Page max-width:** centered, with comfortable side gutters.
- **Vertical rhythm:** consistent spacing between elements, sections, and
paragraphs using the `{spacing.*}` scale.
- **Responsive padding:** larger gutters on desktop, tighter on mobile.
## Shapes
Use rounding intentionally. The scale should encode meaning:
- `{rounded.sm}` — small affordances (badges, tags, checkboxes).
- `{rounded.md}` — surfaces (cards, inputs, popovers).
- `{rounded.lg}` — full overlays (dialogs, sheets).
- `{rounded.pill}` — switches, progress, status chips where the rounded
form carries meaning.
## Components
The `components:` block above maps all 62 components to their default
tokens, grouped by category. The convention:
- **Action** components (button, toggle, toolbar) lead with the accent
color and short, weight-heavy labels.
- **Form** components share a single input surface (`{colors.bg-input}`)
so users learn one affordance for all entry.
- **Navigation** components sit on transparent surfaces — they belong to
the page, not to themselves.
- **Overlay** components elevate to the base background `{colors.bg}` to
feel like a new surface rather than a deeper card.
- **Feedback** components reuse the card surface; only **toast** inverts
to a dark surface for transient prominence.
- **Data Display** components are tight, typographic, and rarely
decorated.
- **Disclosure** and **Layout** components inherit the card surface and
do their work through structure, not color.
Variants (hover, active, focus, open, on) are expressed as separate keys
with a suffix — `button-hover`, `toggle-active`, `tabs-active`,
`switch-on` — so an agent can resolve them by name.
## Do's and Don'ts
- **Do** use `{colors.accent}` only for interactive affordances. Decorative
use dilutes its signal.
- **Do** keep typography to one family. Reach for size and weight before
reaching for a second face.
- **Do** reference tokens in components. Never hard-code hex values, so
themes work without component changes.
- **Don't** introduce shadows for elevation if surface contrast already
carries the hierarchy.
- **Don't** swap `{rounded.sm}` and `{rounded.md}` arbitrarily; the scale
encodes affordance weight.
- **Don't** invent component variants outside the suffix convention —
agents won't find them.
That single file is enough to brief an agent. Hand it the file, ask for "a settings page using the components in DESIGN.md", and the resulting UI will use your typeface, your accent for actions, card-surfaced sections, and the same rounding scale across every component.
Token schema reference
| Type | Format | Example |
|---|---|---|
| Color | # + hex (sRGB) | "#5c4a32" |
| Dimension | number + unit (px, em, rem) | 16px, 1rem, -0.02em |
| Token reference | {path.to.token} | {colors.accent} |
| Typography | object with fontFamily, fontSize, fontWeight, lineHeight, letterSpacing | See template above |
Section order
Sections use ## headings and can be omitted, but those present must appear in this order:
| # | Section | Aliases |
|---|---|---|
| 1 | Overview | Brand & Style |
| 2 | Colors | — |
| 3 | Typography | — |
| 4 | Layout | Layout & Spacing |
| 5 | Elevation & Depth | Elevation |
| 6 | Shapes | — |
| 7 | Components | — |
| 8 | Do's and Don'ts | — |
Valid component properties
backgroundColor, textColor, typography, rounded, padding, size, height, width. Variants like hover, active, or pressed are expressed as separate component entries with a related key name (button-hover, tabs-active).
CLI usage
Install once:
npm install "@google/design.md"
Validate a file (catches broken token references, contrast issues, missing sections):
npx @google/design.md lint DESIGN.md
Compare two versions to detect token-level regressions:
npx @google/design.md diff DESIGN.md DESIGN-v2.md
Export to Tailwind v4 CSS, Tailwind v3 JSON config, or W3C Design Tokens (DTCG):
npx @google/design.md export --format css-tailwind DESIGN.md > theme.css
npx @google/design.md export --format json-tailwind DESIGN.md > tailwind.theme.json
npx @google/design.md export --format dtcg DESIGN.md > tokens.json
Inject the spec into an agent prompt:
npx @google/design.md spec --rules
Linting rules
| Rule | Severity | What it checks |
|---|---|---|
broken-ref | error | Token references that don't resolve |
missing-primary | warning | Colors defined but no primary — agents will auto-generate one |
contrast-ratio | warning | Component bg/text pairs below WCAG AA (4.5:1) |
orphaned-tokens | warning | Color tokens defined but never referenced |
token-summary | info | Summary of tokens defined per section |
missing-sections | info | Optional sections (spacing, rounded) absent |
missing-typography | warning | Colors defined but no typography — agents will use default fonts |
section-order | warning | Sections out of canonical order |
Programmatic API
import { lint } from '@google/design.md/linter';
const report = lint(markdownString);
console.log(report.findings); // Finding[]
console.log(report.summary); // { errors, warnings, info }
console.log(report.designSystem); // Parsed DesignSystemState
Where to put the file
Place DESIGN.md at the root of your repository alongside README.md and AGENTS.md. Agents that follow the convention will discover it automatically. For monorepos, one file per package is allowed.
The DESIGN.md format is at version alpha. Full spec: github.com/google/design.md.