How to order things inside a DSDS document, so every document reads the same way no matter who wrote it.

None of this changes whether a document is valid. The schema accepts any order. Seven warning-only rules (DSDS-17 through DSDS-23 in the advisory tier) point out anything out of order when you run npm run lint. Nothing here can fail npm run check:all. See Tooling for what gets checked automatically and what's left to you.

The schema is the style guide

Write in the order the schema lists them. The order of properties and options in the schema reflect the guidelines' recommendations on how to organize your schema documents. When in doubt, copy how the schema does it.

The patterns behind these rules

Everything below is one of a few ideas, applied to a different part of a document. Learn these and you can usually work out the specific rule.

Field order comes from the schema. List order comes from this guide. Each schema follows the style guide for field order. Which entry, section, or item comes first in a list is something a schema can't express, so this guide describes it.

Broad to specific. The widest thing leads: guidelines before steps, when-to-use before how-to-use, for: all before for: agent, a section about the whole entry before one about a single tag.

Nothing comes before the thing it's built on. Tokens before the themes that override them, themes before the components that use them. Read top to bottom and you meet every idea before anything that depends on it.

Shared fields before specific ones. The fields every kind has come first, then the fields one kind adds. A metadata block works the same way.

Catch-alls go last. $extensions after every real field, the plain section kind after the three specific ones, custom kinds after the five known ones. Anything that exists because nothing else fit goes at the end.

Where no rule decides, keep the order you wrote. Don't alphabetize. Items sharing a level, entries sharing a kind — leave them in whatever order reads best.


1. Base documents and shared entries

A base document is the outermost object. Its fields go in the order seen in base.schema.yaml. shared entries follow shared.schema.yaml.

DSDS-20 checks base documents. DSDS-17 checks shared entries, falling back to shared.schema.yaml when an object has no kind.

Entry order, inside entries[]

When a base document holds several entries, order the entries themselves by kind (the order entries/entry.schema.yaml lists its kind values). This order intends to reflect the "food chain" of systems' elements.

  1. system: Always first since it contextualizes everything contained within.
  2. token: Defines the attributes that themes and components are created from.
  3. theme: Built from tokens, so only makes sense to come after.
  4. component: Built from tokens and themes.
  5. entry: Always last since it can cover a broad set of topics. Feel free to add general onboarding docs after system.

This follows the same idea as §4: Broadest first, and follow the dependency chain. This theoretically means that all prerequisite information is provided up front for an entry.

Within one kind, use whatever order reads best. Avoid arbitrary ordering, such as alphabetical when another order is better for comprehension. For example, a scale reads better as compact, regular, loose than as compact, loose, regular.

entries: - kind: system # id: acme-design-system — what the document is about - kind: token # id: color.action.primary - kind: theme # id: light — overrides the tokens above - kind: theme # id: dark - kind: component # id: button - kind: entry # id: form-layout — a pattern built from components
2. Entries

Follow the high-level order:

  1. Shared entry fields except $extensions defined in entries/entry.schema.yaml.
  2. Then that kind's own fields, defined in entries/.schema.yaml. A custom kind has no file of its own, so should follow the high-level guidance.
  3. Then $extensions. All information that adds to the schema goes last.

If a document is ordered differently, the DSDS-17 warning prints the whole order it expected.


3. metadata

A metadata block joins two lists the same way an entry does: the fields every entry's metadata shares, from metadata/metadata.schema.yaml, then the ones for that kind of entry, from metadata/entry-metadata.schema.yaml or metadata/system-metadata.schema.yaml, then $extensions last. All metadata types work the same way.


4. Sections A section's own fields

A section leads with the fields that say what it is: kind, then for, then the one field its kind adds — framing for guidelines, ordered for steps. The rest follow in the order sections/section.schema.yaml lists them.

That's the same reason kind leads everywhere. These fields tell a reader what they're looking at before they read any of it, so they sit at the top where the reader already is.

Keep each kind together

If an entry has more than one section, put all the sections of the same kind side by side — every guidelines section in a row, then every definitions section, then every steps section, then any plain section. Don't mix them up: guidelines, definitions, guidelines is wrong, even if that's the order you thought of them in.

Kind order: broadest first

Order section kinds like this:

  1. guidelines — the broadest question. Should I use this at all, and how do I use it properly?
  2. definitions — reference material: parts, terms, a glossary. Narrower than guidelines, because it's about this entry's own parts and words. Wider than a set of steps.
  3. steps — one procedure or checklist. The narrowest of the three, because it's one exact sequence rather than general advice.
  4. section (the plain kind) — prose that didn't fit the other three. Last, because it's the fallback.

That's the order sections/section.schema.yaml lists its kind values in. A namespaced custom kind like acme.custom-section isn't in that list, so it sorts after all four. A section with no kind at all is read as section, the default that file declares.

Within guidelines: how broad, then who it's for

Guidelines sorts content by: how broad first, who it's for second. for: agent, framing: when-to-use still comes before a for: all framing: how-to-use, because breadth is settled first. Audience only sorts within one breadth tier — the three above.

Guidelines should lead with when to use, then describe how to use it. That's the order sections/guidelines.schema.yaml lists its framing values in:

  1. framing: when-to-use: Does it make sense to use?
  2. framing: how-to-use: If so, how do you use it? Leaving framing out means this — it's the default that file declares.
  3. Tagged guidelines: A section counts as tagged when it has two or more items and every one of them names the same tag — the accessibility rules, say, or the mobile-only ones. Narrow instruction should follow general information, so these come last whatever their framing is. Two items are the minimum because one item always shares a tag with itself.

Sections in the same breadth tier are then ordered by how broad the audience is. The order sections/section.schema.yaml lists its for values in:

  1. for: all — also what you get by leaving for out, since it's the default that file declares. So an omitted for sorts first, not last.
  2. for: human
  3. for: agent
sections: - kind: guidelines for: all framing: when-to-use items: [...] - kind: guidelines for: all items: [...] # framing: how-to-use (default) - kind: guidelines for: agent items: [...] # same framing as above, narrower # audience — so audience breaks the tie - kind: guidelines for: all title: Accessibility items: [...] # every item here tagged "accessibility" # about one tag, so it follows every # how-to-use section regardless of `for` - kind: definitions context: anatomy items: [...] - kind: steps title: Migration items: [...]
5. Section items An item's own fields

Order an item's fields the way its own schema file lists them.

ShapeIts schema file
A guidelines itemsections/guidelines.schema.yaml
A definitions itemsections/definitions.schema.yaml
A steps itemsections/steps.schema.yaml
Guideline item order, by level

Order items by level, in the order common/requirement-level.schema.yaml lists its values in:

must should may should-not must-not

Order items at the same level in whatever way aids comprehension. Ideally, group subject matter of the same level together. Don't alphabetize items that share a level—that's dumb.

items: - level: must statement: Use semantic tokens instead of raw values. - level: should statement: Prefer the `primary` variant for the page's one main action. - level: may statement: Add a leading icon when it disambiguates the action. - level: should-not statement: Should not pair `loading` with `disabled` in the same interaction. - level: must-not statement: Never stack two primary-variant buttons in the same view.
6. Refs and combos Combos: by subject, then level

Combos sort by: subject first, level second. Every rule about one trait or token sits together, so a reader checking one of them finds the rest in the same place. Within one subject, level breaks the tie, in the order §5 uses for guideline items.

A combo reads as one sentence: this subject, at this strength, with these things. That's the order common/combo.schema.yaml lists its fields in:

  1. subject: What is the rule about? A trait, a token, or an entry.
  2. level: Does it permit or forbid and how strictly?
  3. items: What does the rule apply to?
  4. note: Why does it hold?
Refs: what it points at, then what kind of pointer

A ref answers what it points at before what kind of pointer it is. That's the order common/ref.schema.yaml lists its fields in:

  1. to or href: What does this point at? to for something in this document, href for anything outside it. Exactly one of the two.
  2. rel: What kind of pointer is it?
  3. role: What does the thing being pointed at do here?
  4. note: Anything else worth saying about the connection.

7. A complete example kind: component id: badge name: Badge description: A small status indicator, attached to another element. purpose: Draws attention to a count, state, or category without interrupting the layout it's attached to. metadata: tags: [status, indicator, count] since: 1.2.0 status: {status: stable} sections: - kind: guidelines for: all framing: when-to-use items: - level: should statement: Use to surface a count or state on another element (a notification count, an unread indicator). - level: should-not statement: Do not use as a replacement for a full status message a user needs to act on. - kind: guidelines for: all items: - level: must statement: Keep label text to a single word or number. - level: must statement: Pair with an accessible label when the badge conveys meaning color alone cannot. - level: should statement: Prefer the `dot` variant when the exact count isn't meaningful to the user. - kind: guidelines for: all title: Accessibility items: - level: must statement: Expose the badge's content to assistive technology even when visually decorative. - kind: definitions for: all context: anatomy items: - term: Dot definition: The minimal variant with no visible label, just a colored indicator. related: - to: avatar rel: pairs-with refs: - href: https://github.com/org/ds/react/badge rel: source sourceFiles: - platform: react file: ./src/Badge.tsx specs: - href: ./contracts/badge.contract.json rel: contract traits: - kind: enum id: variant description: Which visual form the badge takes. values: - id: count description: Shows a numeric value. - id: dot description: Shows no value, just presence. combos: - subject: variant.dot level: must-not items: [variant.count] note: A badge is either a dot or a count, never both at once.
Tooling

Seven warning-only rules check this guide. They live in scripts/validate/lint-docs.js, are listed in schema/conformance-rules.yaml as enforcement: advisory, and run with npm run lint.

What's checked

Every rule in this guide is checked except one, and that one can't be. The right-hand column is the warning you'd get.

RuleWhereChecked by
A base document's own fields§1DSDS-20
A shared entry's own fields§1DSDS-17
Entry order inside entries[]§1DSDS-21
An entry's own fields§2DSDS-17
A metadata block's fields§3DSDS-22
A section's own fields§4DSDS-22
Same-kind sections kept together§4DSDS-18
Section kind order§4DSDS-18
Breadth, then audience, among guidelines§4DSDS-18
An item's own fields§5DSDS-22
Guideline items by level§5DSDS-19
A combo's own fields§6DSDS-22
combos[] sorted by subject, then level§6DSDS-23
A ref's own fields§6DSDS-22
Order within one entry kind, or one level§1, §5can't be — it's a judgment call

The tag tier reads the items. Every other sort here looks at a field. DSDS-18 decides whether a section is "about one tag" by intersecting its items' tags, which is the one judgment it makes from content rather than shape. It needs two items to say yes, so a section with a single tagged item is left alone.

Field order has one source: the schema files. The tables on the Schema page are generated from each schema file's own order, DSDS-17, DSDS-20 and DSDS-22 read that same order when they run, and §2 tells you to follow it. So you can read the authoring order off a property table, and the other way round.