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

TypeFormatExample
Color# + hex (sRGB)"#5c4a32"
Dimensionnumber + unit (px, em, rem)16px, 1rem, -0.02em
Token reference{path.to.token}{colors.accent}
Typographyobject with fontFamily, fontSize, fontWeight, lineHeight, letterSpacingSee template above

Section order

Sections use ## headings and can be omitted, but those present must appear in this order:

#SectionAliases
1OverviewBrand & Style
2Colors
3Typography
4LayoutLayout & Spacing
5Elevation & DepthElevation
6Shapes
7Components
8Do'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

RuleSeverityWhat it checks
broken-referrorToken references that don't resolve
missing-primarywarningColors defined but no primary — agents will auto-generate one
contrast-ratiowarningComponent bg/text pairs below WCAG AA (4.5:1)
orphaned-tokenswarningColor tokens defined but never referenced
token-summaryinfoSummary of tokens defined per section
missing-sectionsinfoOptional sections (spacing, rounded) absent
missing-typographywarningColors defined but no typography — agents will use default fonts
section-orderwarningSections 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.