Skip to content

Design system

A design system is not a folder of pictures. It is an agreement between design and engineering about what the interface is made of — settled once, away from any particular screen, so that no screen has to settle it again.

It is an established asset: it exists before any given feature, it is owned and versioned, and features consume it. When a feature finds something it does not cover, that is a change request against it, not a design task inside a story.

That makes it the same kind of artefact as an OpenAPI document, subject to the same three properties from contract-first: explicit, agreed, enforced.

The live version, foundation by foundation, is on the portal: design system.

The single most important structural decision, and the one that decides whether the system survives its second year.

A design system that publishes --purple-600: #7c3aed has published a value. Every consumer now depends on the fact that the thing is purple, and the day the brand changes, the token is a lie and the rename is a breaking change across every screen.

A design system that publishes --color-brand, --color-danger, --color-surface-raised, --color-ink-muted has published a role. Consumers depend on the meaning; the value behind it can change, and a theme is a second set of values behind the same roles rather than a second system.

Layer Example Who may reference it
Primitive purple-600, space-4, text-lg The theme layer only
Semantic role color-brand, color-danger, space-inset-md Components
Component token button-primary-background That component only

The rule that follows: a component may not reference a primitive. It is checkable, which is what makes it a contract clause rather than advice.

Eight, each settling one question. They are listed with what they fix, what they forbid and what enforces them on the design system page; the structural point here is that each one names something it forbids. A foundation that forbids nothing constrains nothing, and a system of such foundations is a style guide with a build step.

The two that are most often left out entirely:

Interaction states. Rest, hover, focus-visible, active, disabled, loading, error, empty, read-only. An undesigned state is not an absent state — it is a state designed badly, at 4pm, by whoever implemented it. Making the list part of the contract is what turns “we forgot the empty state” from a recurring surprise into a missing artefact anybody can see.

Accessibility. Minimum contrast per role pairing (not per colour), a focus ring that survives every theme, a target size floor, heading and landmark structure, and reduced-motion behaviour. These are guarantees the system makes on behalf of every screen, which is the only way they get made at all — see accessibility tests.

Not from taste, and not from a competitor’s system. From user-first findings — accumulated over the life of the system, not re-derived per feature:

Finding Becomes
A step where the person is anxious A confirmation pattern, and an emphasis rule
A step where they are rushed A density decision, and one fewer confirmation
A state card A designed state, with a token set and a story
A cost-of-failure that is high A stronger warning role, and an irreversible-action pattern
A user who cannot see the screen The contrast, focus and announcement guarantees
A usability finding about a shared pattern A change to that pattern, everywhere it is used

A design system built without that column is internally consistent and arbitrary. It will be consistent about the wrong things, which is worse than inconsistency because it is harder to argue with.

The last row is the highest-value input the system ever receives, and the one teams most often waste. A participant who could not find the primary action has told you something about the pattern, not about the screen — and fixing it upstream fixes it on every screen that uses it.

The timing matters too. These findings arrive between features, not during one: a feature consumes the system as it stands, and what it learns feeds the next version of it.

The property that is usually missing. Four mechanisms, in increasing order of how much they cost to set up:

  1. Generated tokens. The values reach code by a build step, never by hand. Design tokens covers the pipeline.
  2. A lint rule against raw values. Colour, spacing, type size and radius literals are rejected outside the theme layer. This is the highest-value hour of work in the whole system.
  3. Contrast checked per role pairing, in the test suite, for both themes.
  4. A story per state, so a state in the contract with no story is a visible gap rather than an assumption.

Where none of these exist, be honest on the page about it. The design system page marks unenforced foundations explicitly, because a gap that is named is a backlog item and a gap that is hidden is a surprise.

The gallery. Beautiful, published, referenced in onboarding, generated from by nobody. It carries the maintenance cost and the appearance of rigour without the property that made it worth adopting.

The value system. Tokens named after what they look like. Survives until the first rebrand, then either the names lie or every consumer changes.

The one-way system. Design proposes, engineering implements, engineering may not propose. Then engineering routes around it — the escape hatch becomes the system, and the real design system is in the application repository.

The per-feature system. Each story designs what it needs, and the “system” is a retrospective description of what was built. Recognisable because a story’s definition of done includes designing a control. This is the failure this hub is mostly about: the system has to be an input before any of the rest works.

The unreachable system. It is established and the change-request queue is three months long, so teams build their own versions “for now”. Turnaround time on a change request is a property of the contract, not an administrative detail.

The system with no forbidding. Every request is accommodated as a new variant. After a year there are eleven button variants, which is the same as having none, except more expensive.

  • Component library is the contract this one is implemented and enforced by.
  • Design tokens is the pipeline that makes it generated rather than retyped.
  • Figma is where the source lives.
  • Journey-first is what becomes possible once this contract holds.