Skip to main content

Design System Contract 1.0

An open specification, JSON Schema and conformance checker for machine-readable component contracts. A contract is one JSON file per component that says what the component accepts, which usages are wrong, as rules a machine can evaluate, and which accessibility claims are proven, by what and when.

Version
1.0, published 25 September 2026
Editor
Petri Lahdelma, Digitaltableteur
Licence
Text CC BY 4.0; schema and code Apache-2.0

Check a design system

Point the checker at a folder of contracts. It reports the level of every contract and of the system as a whole, where the system level is the lowest level of any stable contract.

npx @digitaltableteur/contract-spec path/to/contracts

This site’s own contracts

The Digitaltableteur design system publishes its contracts at /contracts/v1/ and checks them with the same tool. Checked on 2026-11-04 at commit 856512eb5, with evidence older than 180 days counted as stale.

Contracts
197
Stable
108
Accessibility claims re-proven by a machine
525
Declared gaps
286

The system is at Level 3 of 3, Evidenced. 110 contracts reach Level 3; the rest stop at Level 1 because they do not yet record an owner and a last review date, which Level 2 requires. The gaps are listed, not hidden: that is the point of the format.

The specification

1. Why this exists

Design systems describe their components in documentation written for people. Coding agents now read that documentation too, and so do linters, migration tools and procurement reviews. Three problems follow:

  1. Prose cannot be checked. "Don't use an icon-only button without a label" is advice. Nothing can reject code that ignores it.
  2. Claims cannot be told apart. "Accessible" proven by a browser on every commit and "accessible" asserted once in a review last spring are the same sentence on the page.
  3. Nothing expires. A component changes; its documentation, test results and review notes silently stop describing it.

A contract is one JSON document per component that fixes all three: the public API, the usage rules as data a machine can evaluate, and every accessibility claim labelled with how it is verified, backed by records that say when and against which commit the verification ran.

The principle is simple: nothing an agent or a reviewer reads about a component is hand-asserted without saying so. A claim is either proven by a record anyone can re-check, dated by the person who made it, or declared as a gap.

2. Conventions

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as described in RFC 2119 and RFC 8174 when, and only when, they appear in all capitals.

A contract is a JSON document conforming to the schema. A system is a set of contracts published together. A checker is software that evaluates contracts against this specification; contract-check is the reference checker.

3. The contract document

A contract MUST be a JSON object that validates against the 1.0 schema. The schema is normative for structure; this section states intent.

FieldRequiredMeaning
specVersionyesAlways "1.0" for this version.
nameyesThe name consumers import. Dotted names (Tabs.Trigger) address compound parts.
statusyesexperimental, alpha, beta, stable or deprecated.
descriptionyesWhat the component is for, in one or two sentences.
propsyesThe public props API. May be empty.
packagenoThe package name and the exact import statement to write.
rulesnoMachine-checkable usage rules (section 4).
accessibilitynoAccessibility criteria (section 5). Required in practice for Level 2.
governancenoWho owns the contract and when a person last read it end to end.
deprecationwhen deprecatedWhy, and the migration path.
sourcenoRepository paths of the implementation, for commit-based freshness.

Fields beginning with x- are extensions. Checkers MUST ignore extensions they do not understand. Any other unknown field is a schema error, so that a misspelt field fails loudly instead of being silently ignored.

3.1 Props

Each prop MUST declare a type. A prop whose type is union MUST list its allowed literal values; a union without values tells an agent nothing it can check. A prop MAY declare optional, default and description.

A deprecated prop MUST carry a deprecated object with a reason. To reach Level 2 it MUST also name a replacement (a prop a codemod can target) or a removeIn version (a date a release gate can hold). A deprecation without a migration path is prose.

3.2 Status

stable is a promise to consumers. A system's conformance level is computed over its stable contracts (section 7), so a system cannot claim a level by keeping its weakest components out of stable, and cannot reach one while a stable component falls short.

4. Usage rules

A rule states a condition on one usage of the component and what must or must not be present when it holds.

{  "id": "icon-only-needs-name",  "when": { "icon": { "present": true }, "children": { "absent": true } },  "requireAnyOf": ["accessibleName", "aria-label"],  "reason": "An icon-only button has no accessible name.",  "severity": "error"}
  • when maps prop names to exactly one matcher: present, absent, equals (a literal) or oneOf (a list of literals). The rule fires when every matcher holds.
  • children is a pseudo-prop for element children.
  • When a rule fires, a checker MUST report each forbid prop that is present, MUST report requireAnyOf when none of its props is present, and MUST report each requireAllOf prop that is absent.
  • equals and oneOf MUST NOT match a value the checker cannot state as a literal (for example an expression it does not evaluate). A rule must never fire on something the checker cannot prove.
  • severity is error or warning. evidence MAY say where the rule comes from, for example a runtime warning in the component source.

Rules that cannot be expressed this way stay in documentation. The grammar is deliberately small: it covers the rules that break builds and accessibility most often (missing names, mutually exclusive props, props that only make sense together) and nothing a checker would have to guess about.

5. Accessibility criteria

accessibility.criteria is a list of statements about the component, each with a verification mode:

verificationMeaningRequired fields
automatedA machine re-proves it; records are attached.check, evidence
manualA person checked it on a known date.reviewedAt
unverifiedA declared gap. Not a claim.none
  • check is the command that re-proves an automated criterion.
  • wcag MAY list the WCAG 2.x success criteria the check exercises. Listing a success criterion is not a claim that it is met: automated checks can test part of a criterion, never prove conformance on their own.
  • Publishers SHOULD list known gaps as unverified rather than omit them. An absent criterion reads as "not applicable"; an unverified one reads as what it is.

6. Evidence

An evidence reference points at a machine-written record of one run:

{  "artifact": "evidence/button-default.axe.json",  "sourceCommit": "4f2a9c1e7b3d5a6c8e0f1a2b3c4d5e6f7a8b9c0d",  "capturedAt": "2026-09-20T08:30:00.000Z",  "passed": true,  "runner": "ci"}
  • artifact is a path or an https URL. Relative paths resolve against the evidence root, which a checker MUST let the user set and SHOULD default to the directory containing the contract.
  • sourceCommit is the commit the run checked. capturedAt is when it ran.
  • A checker MUST treat evidence as invalid when: passed is not true; capturedAt is older than the freshness window or in the future; a local artifact does not exist; or a JSON artifact records a commit (sourceCommit or sourceSHA) or time (capturedAt or generatedAt) that disagrees with the reference. A contract cannot claim a fresher run than its record shows.
  • The default freshness window is 180 days. A checker MUST let the user change it.
  • A checker MAY also offer commit-based freshness: when the contract lists source paths, evidence is stale if any of those paths changed after sourceCommit. This is the stronger test; time windows are the portable floor.

7. Conformance levels

A contract meets the highest level whose requirements it and every lower level satisfy.

LevelNameRequirements
1DescribedValidates against the schema.
2CheckableLevel 1, plus governance with an owner and a review date, at least one accessibility criterion, and every deprecation carries a migration path.
3EvidencedLevel 2, plus at least one automated criterion; every automated criterion has valid, fresh evidence (section 6); every manual criterion was reviewed within the freshness window.

A system's level is the lowest level met by any of its stable contracts. A system with no stable contracts is measured over its non-deprecated contracts. A checker SHOULD report the distribution of levels and the count of automated, manual and unverified criteria next to the system level, because a single number hides where the gaps are.

A publisher claiming conformance SHOULD state the level, the specification version, the checker and its version, the freshness window, and the date of the check, for example: "Design System Contract 1.0, Level 3, contract-check 1.0.0, 180-day window, checked 2026-09-25."

8. Relationship to other standards

  • W3C Design Tokens (DTCG). Tokens describe values; contracts describe components. A contract MAY reference token names in extensions; this specification does not define token formats.
  • WCAG 2.2 and EN 301 549. Criteria map to WCAG success criteria for orientation only (section 5). EN 301 549 v4 adopts WCAG 2.2 and numbers web requirements as clause 9 plus the WCAG number, so the mapping carries over.
  • Model Context Protocol. A design-system MCP server can serve contracts and evaluate section 4 rules for an agent before its code is written. This specification defines the data; it does not define tools.

9. Versioning

This specification follows semantic versioning. A minor version MAY add optional fields and reporting detail; it MUST NOT make a valid 1.0 contract invalid or lower its level. Anything else is a major version.

10. Reference implementation

npx @digitaltableteur/contract-spec path/to/contracts --level 2

The Digitaltableteur design system publishes its own contracts in this format at public/contracts/v1/ in its repository and checks them with the same tool on every push, including the levels it does not yet meet.

Why contracts matter once AI agents write your UI is argued in Design systems for bots (external link) on petrilahdelma.com.

Stable contracts

The 108 stable contracts and the level each one reaches. Every name opens the contract itself.

ComponentLevelAutomatedManualGaps
AboutPageContent3 Evidenced311
AlertBanner3 Evidenced312
ArticleContent3 Evidenced311
ArticleShareSection3 Evidenced312
Author3 Evidenced310
AuthorBio3 Evidenced311
Avatar3 Evidenced311
Badge3 Evidenced311
BlogCategoryFilter3 Evidenced312
BlogMediaImage3 Evidenced311
BlogNav3 Evidenced311
Breadcrumb3 Evidenced312
Button3 Evidenced122
Card3 Evidenced212
CategoryFilter3 Evidenced312
Checkbox3 Evidenced312
CheckboxGroup3 Evidenced312
ClientLogoMarquee3 Evidenced311
Combobox3 Evidenced312
ContactFormEditorial3 Evidenced312
ContactHero3 Evidenced310
ContactInquiryPanel3 Evidenced312
ContactPageContentEditorial3 Evidenced311
Container3 Evidenced311
CTASection3 Evidenced311
DesignSprintsSection3 Evidenced311
Divider3 Evidenced311
DonnyAvatar3 Evidenced311
EmptyState3 Evidenced312
EnhancedProjectCard3 Evidenced312
ExpandableSection3 Evidenced322
FileUpload3 Evidenced312
FilterChip3 Evidenced312
FormField3 Evidenced312
FormFieldEditorial3 Evidenced311
Gallery3 Evidenced322
Grid3 Evidenced310
GridBlock3 Evidenced310
GroupLabel3 Evidenced311
HelperText3 Evidenced311
HeroSection3 Evidenced310
HighlightSection3 Evidenced311
HomeHero3 Evidenced312
Icon3 Evidenced211
IconButton3 Evidenced312
Kbd3 Evidenced311
Label3 Evidenced311
LanguageSwitcher3 Evidenced312
Link3 Evidenced312
List3 Evidenced311
ListItem3 Evidenced311
Logo3 Evidenced311
MarkdownMessage3 Evidenced312
Menu3 Evidenced312
Modal3 Evidenced312
MultiCombobox3 Evidenced312
NavLink3 Evidenced312
NewsBulletin3 Evidenced312
PageLayout3 Evidenced310
Pagination3 Evidenced312
PhoneInput3 Evidenced312
PricingCalculator3 Evidenced312
PricingPageContent3 Evidenced312
ProcessBlock3 Evidenced311
Progress3 Evidenced311
ProjectCard3 Evidenced321
ProjectGallery3 Evidenced322
ProjectNav3 Evidenced311
ProofBlock3 Evidenced311
ReadingProgress3 Evidenced311
Section3 Evidenced310
SecureCVDownload3 Evidenced312
Select3 Evidenced312
SelectableCard3 Evidenced312
SelectOption3 Evidenced312
ServiceCard3 Evidenced311
ServicesBlock3 Evidenced311
ServicesSection3 Evidenced311
SiteFooter3 Evidenced312
SiteHeader3 Evidenced312
SiteTree3 Evidenced312
Skeleton3 Evidenced311
SkipLink3 Evidenced312
SlideButton3 Evidenced322
SocialShare3 Evidenced312
Spinner3 Evidenced311
Stack3 Evidenced311
StatusDot3 Evidenced311
StoryBlock3 Evidenced311
Switch3 Evidenced312
Table3 Evidenced312
TableCell3 Evidenced311
TableHeaderCell3 Evidenced312
TableRow3 Evidenced311
Tabs3 Evidenced312
TeamBlock3 Evidenced311
Text3 Evidenced121
TextArea3 Evidenced312
TextInput3 Evidenced312
Timestamp3 Evidenced311
Title3 Evidenced121
Toast3 Evidenced311
ToastStack3 Evidenced311
ValueCard3 Evidenced311
VisuallyHidden3 Evidenced310
WorkMagneticField3 Evidenced311
WorkNav3 Evidenced311
WorkPreviewSection3 Evidenced311