A standard, machine-readable format for design system documentation.
DSDS defines a JSON-based format for documenting the eight entity types of a design system:
- Components — Anatomy, API, variants, states, design specifications, best practices, accessibility, content
- Tokens — Semantic meaning, platform mappings, contrast ratios, usage rules
- Token Groups — Hierarchical organization of tokens into families and sub-families
- Themes — Named sets of token value overrides for color modes, density, brand variants
- Foundations — Broad design domains: color, typography, spacing, elevation, motion, shape, accessibility, and content — with principles, scales, motion definitions, and best practices
- Patterns — Broad interaction patterns like navigation, error messaging, and empty states — with anatomy, variants, states, interactions, and content
- Guides — Long-form, reading-oriented documentation like getting-started walkthroughs, contribution guides, tutorials, and migration guides — with narrative sections, step-by-step procedures, and best practices
- Chunks — Pre-composed blocks of code that capture a pattern built from the system's components — copy-paste starting points like a search bar, settings form, or confirmation dialog — with guidelines, use cases, and the code itself
All structured docs live in one document block system. Each entry is a typed container with a kind tag. The kinds cover guidelines, anatomy, API specs, variants, states, accessibility, examples, design specifications, principles, scales, motion, content, interactions, narrative sections, and step-by-step procedures.
The goal is simple: make design system docs structured, portable, and easy for tools to read. The tool can be a docs site, a linter, a code assistant, or a person reading JSON.
Design system documentation today is trapped in tools. It lives in Notion, Storybook, Zeroheight, Confluence, or custom-built sites. Each one has its own structure and its own rules, and none of them work together.
This creates real problems:
- Migration is expensive. Switching docs tools means rebuilding everything from scratch.
- Consistency is accidental. With no shared structure, every team invents its own format. Readers must relearn what to expect each time.
- Tooling can't help. Tools can't reliably read docs from other tools, since there is no shared schema to build against.
- AI needs structure. LLMs and code assistants work far better with structured, predictable docs than with loose prose.
DSDS addresses these problems by defining a standard format that is:
| Quality | What it means |
|---|---|
| Structured | Every section has a defined shape. Consumers know what to expect. |
| Machine-readable | Tools can parse, generate, validate, and transform documentation. |
| Portable | Documentation is decoupled from any specific tool or platform. |
| Extensible | Vendor metadata can be added without breaking interoperability. |
| Complementary | Works alongside the W3C Design Tokens Format, not against it. |
The W3C Design Tokens Community Group defines a format for trading token values between tools. DSDS defines a format for the documentation around them — how to read and apply those tokens, plus the components, foundations, and patterns that use them.
The two formats are built to work together. DSDS does not duplicate token values or platform identifiers. The W3C Design Tokens Format file is the source of truth for values. Use the source property on a token entity to link it back to its DTCG definition.
Note
Credit where due: DSDS's conformance and rules design follows the trail blazed by the Adobe Spectrum Design Data specification. The layered model — structural rules enforced in the schema itself, quality rules in a catalog with stable IDs (rules/rules.yaml), and testable criteria with declared verification modes — is a Spectrum-style approach, and Spectrum's schema evolution docs informed how DSDS thinks about versioning. Prior art this good deserves a shoutout.
The authoritative reference for every schema, field, and document-block type is the documentation site at designsystemdocspec.org. Property tables there come straight from the schema JSON, so they cannot drift from the code.
Start here:
- Overview — What DSDS is, the entity model, and how the pieces fit together.
- Quick Start — Document structure, entity kinds, the document-block system, and minimal examples for every entity type.
- Humans & agents — How a DSDS document serves both people and AI agents, and when to use
agentDocumentBlocksalongsidedocumentBlocks. - Schema Architecture — The full schema reference. Covers document structure, entity types, the
agentsproperty, status, the document-block system, links, extends, extensions, naming conventions, and conformance levels, all with live property tables sourced from the schema. - Conformance — Conformance classes, enforcement tiers, and the generated index of every normative statement in the schemas.
- Interoperability — How DSDS composes with the W3C Design Tokens format, Custom Elements Manifest, and Storybook: the documentation layer over existing sources of truth.
- Stability & 1.0 — The stability contract: version semantics, the deprecation policy, the enumerated breaking backlog, and the criteria for declaring 1.0.
- Interactive Samples — Side-by-side JSON ↔ rendered docs for real-world entities (component, token, theme, foundation, pattern).
Per-schema reference pages sit next to the narrative pages — e.g. entities/component, document-blocks/guidelines, common/use-cases. Each page is built from its matching spec/schema/**/*.schema.json file.
You can also build the site locally to browse offline or while you work on the spec. Run npm run build and open site/dist/index.html.
This README leaves out schema field listings, document-block catalogs, default values, enforcement levels, and example payloads on purpose. Those live on the documentation site as a single source of truth.
spec/
├── schema/
│ ├── dsds.schema.json # Root JSON Schema (anyEntity, entityGroup, fileRef)
│ ├── dsds.bundled.schema.json # Auto-generated single-file bundle
│ ├── common/ # Shared primitives
│ │ ├── criterion.schema.json # criterion, conformanceLevel, verificationMode, criterionCheck, criterionFixture, reference
│ │ ├── dated-note.schema.json # isoDate, plainNote (shared date+note leaves)
│ │ ├── entity-ref.schema.json # entityRef, entityIdentifier, entityRole (the one way to point at an entity)
│ │ ├── example.schema.json # example
│ │ ├── extends.schema.json # documentExtends, entityExtends
│ │ ├── extensions.schema.json # $extensions
│ │ ├── link.schema.json # link
│ │ ├── presentation.schema.json # presentationImage, presentationVideo, presentationCode, presentationUrl
│ │ ├── relationship.schema.json # relationship, relationType, relationships
│ │ ├── rich-text.schema.json # richText (markdown string)
│ │ ├── status.schema.json # statusValue, platformStatus
│ │ ├── system-info.schema.json # systemInfo
│ │ ├── token-overrides.schema.json # tokenOverrides (shared token-override map)
│ │ └── use-cases.schema.json # useCases, useCase
│ ├── metadata/ # Entity metadata fields (one file per field)
│ │ ├── metadata.schema.json # entityMetadata (the aggregating object)
│ │ ├── aliases.schema.json # aliases
│ │ ├── category.schema.json # category
│ │ ├── doc-origin.schema.json # docOrigin, docOriginValue, authorshipValue (initial draft)
│ │ ├── governance.schema.json # governance, owner, lastReviewed (initial draft)
│ │ ├── last-updated.schema.json # lastUpdated
│ │ ├── links.schema.json # links
│ │ ├── preview.schema.json # preview
│ │ ├── since.schema.json # since
│ │ ├── status.schema.json # status
│ │ ├── summary.schema.json # summary
│ │ ├── tags.schema.json # tags
│ │ └── thumbnail.schema.json # thumbnail
│ ├── entities/ # Entity types
│ │ ├── chunk.schema.json # chunk
│ │ ├── component.schema.json # component
│ │ ├── foundation.schema.json # foundation
│ │ ├── guide.schema.json # guide
│ │ ├── pattern.schema.json # pattern
│ │ ├── theme.schema.json # theme, tokenOverride
│ │ └── token.schema.json # token, tokenGroup
│ └── document-blocks/ # Document block types
│ ├── document-blocks.schema.json # Scoped unions (componentDocumentBlock, generalDocumentBlock, etc.)
│ ├── accessibility.schema.json # accessibility, keyboardInteraction, ariaAttribute, colorContrast
│ ├── anatomy.schema.json # anatomy, anatomyEntry
│ ├── api.schema.json # api, apiProperty, apiEvent, apiSlot, etc.
│ ├── checklist.schema.json # checklist, checklistItem
│ ├── content.schema.json # content, contentLabelEntry, localizationEntry
│ ├── design-specifications.schema.json # designSpecifications, spacingSpec, sizingSpec, typographySpec, etc.
│ ├── guidelines.schema.json # guidelines, guidelineEntry
│ ├── imports.schema.json # imports, importEntry
│ ├── interactions.schema.json # interactions, interactionEntry
│ ├── motion.schema.json # motion, motionEntry, motionDuration
│ ├── principles.schema.json # principles, principleEntry
│ ├── scale.schema.json # scale, scaleStep
│ ├── sections.schema.json # sections, sectionEntry
│ ├── states.schema.json # states, stateEntry
│ ├── steps.schema.json # steps, stepEntry
│ └── variants.schema.json # variants, flagVariant, enumVariant, variantValue
└── examples/
├── starter-kit.dsds.json # Complete document with components, tokens, foundations, patterns
├── minimal/ # Lightweight examples showing the floor of documentation
├── common/ # Per-definition examples for common primitives
├── metadata/ # Per-field examples for entity metadata
├── entities/ # Per-definition examples for entity types (incl. empty-state pattern)
└── document-blocks/ # Per-definition examples for document block types (incl. motion, content)
rules/
└── rules.yaml # Quality rules catalog (stable DSDS-NNN IDs; drives lint-docs.js)
taxonomy/
└── taxonomy.yaml # Writing taxonomy & glossary — one term, one meaning, everywhere
scripts/
├── bundle.js # Generates dsds.bundled.schema.json from split schemas
├── validate.js # Validates all example files against the bundled schema
├── lint-docs.js # Editorial doc lint (warning tier; rules from rules/rules.yaml)
├── sync-examples.js # Syncs markdown dsds:include directives with example JSON
├── migrate-to-0.7.js # Migrates v0.5.x / v0.6 documents to the v0.7 shape
├── migrate-to-0.8.js # Migrates v0.7.x documents to v0.8 (criterion fixture outcomes)
├── migrate-to-0.10.js # Migrates v0.8.x / v0.9.x documents to v0.10 (levels, entity refs, accessibility data)
├── build-site.js # Generates the static specification site (orchestrator)
├── build-samples.js # Generates the interactive sample viewer from example JSON
├── render-entity.js # Server-side entity rendering used by build-samples.js
├── render-prop-table.js # Shared schema-to-HTML property table renderer (used by build-site + MDX)
├── compile-mdx.mjs # MDX content compiler for narrative pages (overview, quickstart, schema-architecture)
├── nav.js # Shared navigation builder for spec pages
└── visualize.js # Generates schema architecture diagram (SVG + Mermaid)
site/
├── tokens.css # Centralized design tokens (colors, fonts, spacing, radii, etc.)
├── style.css # Core site stylesheet (layout, nav, typography — imports tokens.css)
├── pages.css # Shared styles for standalone pages (samples, quickstart)
├── components/ # Reusable HTML web components (ES modules)
│ ├── index.js # Barrel file — imports all components, registers custom elements
│ ├── _shared.js # Shared utilities (createShadow, esc, BASE_RESET, FONT)
│ ├── badge.js # <ds-badge> — status/category badges
│ ├── back-to-top.js # <ds-back-to-top> — scroll-to-top link
│ ├── button.js # <ds-button> — button with variants and sizes
│ ├── card.js # <ds-card> — bordered content card
│ ├── code.js # <ds-code> — syntax-highlighted code (block + inline)
│ ├── cross-refs.js # <ds-cross-refs> — cross-reference links
│ ├── def-example.js # <ds-def-example> — definition example block
│ ├── def-index.js # <ds-def-index> — page-level definition index
│ ├── def-section.js # <ds-def-section> — definition section container
│ ├── footer.js # <ds-footer> — page footer
│ ├── heading.js # <ds-heading> — section heading (h1–h6) with anchor
│ ├── note.js # <ds-note> — callout/warning box
│ ├── prop-table.js # <ds-prop-table> + <ds-prop> — schema property table
│ ├── schema-header.js # <ds-schema-header> — schema page header
│ ├── scrollspy.js # <ds-scrollspy> — scroll position tracker
│ ├── sidebar.js # <ds-sidebar> — collapsible sidebar panel
│ ├── sidenav.js # <ds-sidenav> + <ds-nav-group> + <ds-nav-link>
│ ├── table.js # <ds-table> — styled table wrapper
│ ├── tabs.js # <ds-tabs> + <ds-tab> — tabbed content
│ ├── toc.js # <ds-toc> — auto-built table of contents
│ ├── toolbar.js # <ds-toolbar> — sticky top toolbar
│ └── type-ref.js # <ds-type-ref> — type reference link
├── samples-template.html # Template for the interactive sample viewer
└── dist/ # Generated HTML site (auto-generated)
Visit designsystemdocspec.org for the canonical reference, or see the Documentation section above for entry points. Property tables, type definitions, and cross-references are all rendered live from the schema.
The spec/examples/ directory contains validated example files:
starter-kit.dsds.json— A complete document with components, tokens, a foundation, and a pattern, showing the full architecture.minimal/— Lightweight examples (8–30 lines each) showing the floor of documentation for each entity type.interop/— Interoperability pairs: CEM's sample manifest beside the DSDS component document it converts to, and a DTCG token file beside the DSDS token document that references it. Embedded on the site's Interoperability page via drift-guarded includes.entities/component.json— A full Button component with anatomy, API, variants (flag and enum types), states, design specs, guidelines, purpose, and accessibility.entities/empty-state-pattern.json— An Empty State pattern demonstrating anatomy, variants, states, interactions, content guidelines, and localization on a pattern entity.entities/foundation.json— A Spacing foundation with principles, scale, motion definitions, and guidelines.entities/token.json— A semantic color token with source reference, category, and guidelines.entities/token-group.json— A hierarchical color palette with nested hue families and grade scales.entities/theme.json— A dark mode theme with token overrides, purpose, guidelines, and accessibility.entities/pattern.json— An error messaging pattern with interactions, component references, and accessibility.
Install dependencies and run the validation suite:
npm install
npm run validateThis runs three steps automatically: syncs example includes, bundles the schema, and validates all example files.
To validate your own DSDS file:
npx ajv validate -s spec/schema/dsds.bundled.schema.json -d my-system.dsds.jsonReference https://designsystemdocspec.org/v0.13.0/dsds.bundled.schema.json from your DSDS files via the $schema keyword to get editor autocompletion and inline validation. See the Quick Start docs page for the single-entity and multi-entity document shapes.
Schema validation answers "is this document allowed?" The doc lint answers "is this documentation good?" It flags quality gaps — guidelines without a rationale or evidence, components and patterns without use cases, entities without a description — and always exits 0:
npm run lint:docs # lints spec/examples/
node scripts/lint-docs.js my-system.dsds.json # lint your own files or directoriesnpm run build
# Open site/dist/index.htmlThe site is auto-generated from the schema JSON files. Property tables, type descriptions, and cross-references all come directly from the schemas. The prose modules add context and examples.
After changing any schema file, regenerate the bundled version:
npm run bundleGenerate a diagram showing how all schema files relate to each other:
npm run visualizeThis produces:
site/dist/schema-architecture.mmd— Mermaid source (renders natively on GitHub)site/dist/schema-architecture.svg— Clean SVG with no CSS, compatible with Figma
Options:
node scripts/visualize.js --format=svg # SVG only
node scripts/visualize.js --format=mmd # Mermaid source only
node scripts/visualize.js --layout=root,entities,guidelines,common # Custom column order
node scripts/visualize.js --layout=root+common,entities,guidelines # Stack groups with +
node scripts/visualize.js --no-edges # Hide dependency edgesGenerate a side-by-side documentation page that shows how DSDS JSON maps to rendered output:
npm run build-samplesThis reads example JSON files from spec/examples/ and produces site/dist/samples.html — a self-contained page with:
- Tabs for each entity type: Button Component, Color Token, Error Messaging Pattern, Spacing Foundation, Dark Theme
- Side-by-side layout: raw JSON on the left, rendered documentation on the right
- Element-level highlighting: hover over any rendered element to see its corresponding JSON, and vice versa
- Color-coded section bars mapping JSON sections to their visual output
- Off-screen indicators when highlighted code is scrolled out of view
To add a new example tab, add an entry to the SAMPLES array in scripts/build-samples.js:
{
file: "entities/component.json", // path relative to spec/examples/
key: "component", // top-level key to extract
id: "component", // unique tab identifier
label: "Button Component", // human-readable tab label
}Narrative content (site/content/*.mdx — the Overview, Quick Start, and Schema Architecture pages) is compiled to HTML by scripts/compile-mdx.mjs. Authors write prose alongside two custom shortcodes:
<ds-example file="..." label="..." />— inlines a JSON example fromspec/examples/minimal/as a fenced code block.<ds-prop-table schema="..." def="..." />— renders the property table for any$defsentry directly from the schema. Per-schema docs pages and narrative pages share the same renderer (scripts/render-prop-table.js), so a description change in a schema flows to every page automatically.
Example:
### Anatomy entry
A component or pattern's anatomy entry has the following shape:
<ds-prop-table schema="document-blocks/anatomy" def="anatomyEntry" />Special values:
schema="root"— loadsspec/schema/dsds.schema.json.def="$root"— renders the schema's top-levelproperties(used for schemas that don't use$defsat all).
The Quick Start page (site/content/quickstart.mdx) is compiled the same way as every other narrative page. There is no longer a separate build command for it: run npm run build and the page is regenerated at site/dist/quickstart.html.
The spec version lives in three coordinated places:
spec/schema/dsds.schema.json#/properties/dsdsVersion/const— the single source of truth. The bundle script, the nav, every page title, and the versioned dist directory all derive from this value.- The
$idURL on every schema file — e.g.,https://designsystemdocspec.org/v0.13.0/metadata/last-updated.schema.json. Every example document's$schemafield and every"dsdsVersion"literal inside example JSON has to track the same version. package.json#version— the npm package version. Conventionally kept in lockstep withdsdsVersion.const.
The scripts/bump-version.js script keeps the first two in sync across all 52 schema files, every example, and the README. package.json is handled separately because it's not a schema-consumer file.
The MDX content pages (site/content/*.mdx) never hardcode a version. They reference it through the {{VERSION}} token, which scripts/compile-mdx.mjs substitutes at build time from dsds.schema.json#/properties/dsdsVersion/const — the single source of truth above. Use {{VERSION}} anywhere a page needs the spec version: page titles and headings, $schema URLs (https://designsystemdocspec.org/v{{VERSION}}/…), inline "dsdsVersion": "{{VERSION}}" examples, and prose.
This means a version bump propagates to every site page on the next npm run build with no string rewriting — so bump-version.js deliberately does not touch the MDX files. Do not hardcode a version in MDX, or it will silently drift the next time the spec is bumped. (Real example documents under spec/examples/ are the exception: they carry literal, validatable versions and are version-stamped by bump-version.js.)
| Change | Spec version | New URL path? | Old URL path |
|---|---|---|---|
| Schema additions (new optional fields, new union members, new entity kinds) | Bump patch (e.g. 0.2 → 0.2.1) |
Yes — published at /v0.2.1/ |
/v0.2/ stays untouched as a historical artifact |
| Breaking changes (renamed/removed fields, new required fields, tightened constraints) | Bump minor or major (e.g. 0.2.1 → 0.3) |
Yes — published at /v0.3/ |
All older versions stay untouched |
| Documentation-only edits (typos, prose clarifications, no schema or example changes) | No bump | No | No change |
The versioned dist directories (site/dist/v<n>/dsds.bundled.schema.json) are immutable public contracts. npm run build refuses to overwrite an existing one. Every consumer that pins $schema to that URL relies on the file there never changing.
This is the exact sequence for cutting a release that includes schema changes. Skip steps 1–3 for a documentation-only release.
-
Make your schema changes under
spec/schema/. Add new files, edit existing ones, or update the unions inmetadata/metadata.schema.json/document-blocks/document-blocks.schema.jsonas needed. -
Add or update examples under
spec/examples/. Per-definition example files live inspec/examples/{common,document-blocks,entities,metadata}/<schemaName>.jsonand are picked up automatically by the docs site for each schema page. Update full-document examples (starter-kit.dsds.json, etc.) and entity examples (entities/component.json, etc.) to demonstrate the new feature in context. -
Update the README project structure listing under
## Project Structureif you added or removed schema files. (The site nav auto-discovers schemas, so no MDX updates are needed for that.) -
Bump
package.json#versionto the target version (e.g.0.2.0→0.2.1). -
Add a CHANGELOG entry at the top of
CHANGELOG, mirroring the format of the prior release. Include a one-line header noting where the bundled schema is now served (e.g., "Schema files are now served athttps://designsystemdocspec.org/v0.13.0/...") and an "Additions" or "Breaking changes" section describing every schema-visible change. -
Run the version bump. Preview the change first:
node scripts/bump-version.js 0.2.1 --dry-run
Apply it:
node scripts/bump-version.js 0.2.1
This rewrites
dsdsVersion.const, the root schema title, every$idURL across the 52 split schemas, every example's$schemaURL and"dsdsVersion"literal, and the README — then regeneratesspec/schema/dsds.bundled.schema.jsonso the bundle reflects the new version. The MDX content pages need no rewriting; they pick up the new version from{{VERSION}}on the nextnpm run build(see Version templating in MDX content). The script is drift-tolerant: it migrates any stale/v<X>/URL it finds, not just the one currently indsdsVersion.const. -
Build the site.
npm run build
This regenerates every page under
site/dist/and publishes a newsite/dist/v<new-version>/dsds.bundled.schema.json. If a versioned directory for the new version already exists with a differing bundle, the build will print a warning and skip the copy — delete the file manually and rerun the build to intentionally re-publish. -
Validate.
npm run validate
All example documents and per-definition examples must pass. A failure here usually means an example file uses an old field name or a newly required field is missing.
-
Spot-check the rendered site. Confirm the version reads correctly in three places:
- Page
<title>tags (e.g.,DSDS Last Updated Metadata — DSDS 0.13.0). - The nav title (
Design System Documentation Spec 0.13.0). - The footer (
Design System Documentation Spec (DSDS) 0.2.1 — Draft Specification).
The new schema page should exist at
site/dist/<group>-<name>.html(e.g.,site/dist/metadata-last-updated.html), and the versioned bundle should exist atsite/dist/v<new-version>/dsds.bundled.schema.json. - Page
-
Commit. Stage the schema changes, example updates, README, CHANGELOG,
package.json, and the entiresite/dist/tree (including the new versioned subdirectory) in one commit. The historical versioned subdirectories undersite/dist/v<older>/must stay untouched.
For a typo fix or prose clarification that doesn't touch any schema or example:
npm run build # regenerates HTML only; no version bump, no new versioned bundleNo changelog entry, no version bump, no new /v<n>/ artifact. Commit the regenerated HTML.
- Structure enables quality. A defined format sets a floor for quality and completeness.
- Guidance without justification is incomplete. Every best practice must answer "why?"
- Documentation should be portable. Teams change tools. Docs should survive the move.
- Education is a responsibility. Explain what, why, and how.
- Specificity over subjectivity. "Use sparingly" is not guidance. "Limit to one per surface" is.
- Schema is the source of truth. Property tables come from schema JSON, not hand-written copy. Prose gives context; schemas give structure.
This is an early-stage specification (currently DSDS 0.13.0). Feedback is welcome:
- Open an issue for questions, suggestions, or problems with the spec.
- Open a PR for proposed changes to the spec, schema, or examples.
- Afyia Smith — the
governanceanddocOriginmetadata schemas (initial drafts, introduced in 0.12.1 and subject to change).
This project is open source. See LICENSE for details.