Skip to content

Governance

Matter's design system is small enough that one maintainer can hold the visual identity in their head. It's also widely consumed enough that every change touches several downstream surfaces. Governance is what keeps both true.

Read this page before opening a PR that adds a token, a component, a variant, or a pattern. Bug fixes and copy edits don't need a proposal — direct PRs are welcome.

The five-step proposal workflow

  1. State the problem in one sentence. "I need a Card variant that pairs with a left-rail icon column." The problem should be a user-facing capability, not "I want a new visual treatment."
  2. Show three real screens that need it. Mocks or live URLs. The bar is "this appears in at least three real screens, today or imminently." One-off needs don't justify a system addition.
  3. Propose the minimum surface. New prop on an existing component beats new component. New tone on an existing variant beats new variant. New token only when no composition reaches the goal.
  4. Open the PR with the rubric checklist. Every component page follows the 15-section rubric. New tokens land in packages/tokens/src/index.ts first, then propagate.
  5. Pair with the maintainer for the visual review. A 15-minute synchronous review lands faster than a comment thread. Use it.

What's in scope vs. out

In scopeOut of scope (consumer responsibility)
Token additions, deprecations, renamesApp-specific styles in apps/app / apps/web
Component additions, variants, removalsPage-level layouts in product surfaces
Pattern additions and migrationsOne-off animations specific to a single page
Voice and tone rule changesMarketing copy in @repo/cms
Lifecycle-phase taxonomy changesAPI resource shapes (lives in openapi.yaml)
Cross-package brand identity changesPer-app Tailwind utility classes that compose system tokens

The boundary: if it ships through @matter/tokens, @matter/components, or @repo/brand, the design system owns it. If it lives in an app or a domain package, the consuming team owns it.

Proposal templates

New token

**Token name.** `--surface-glass-pressed` (proposed)

**Problem.** When the user clicks a Glass card, the pressed state has no
canonical fill — every consumer is inlining their own rgba.

**Three screens that need it.**
1. Dashboard board-pack click target (apps/app/.../board/pack-row.tsx)
2. Marketing pricing card hover-into-press (apps/web/pricing)
3. Composer chip pressed state when the picker is open (Composer)

**Proposed value.** `color-mix(in srgb, var(--ink-12) 80%, var(--surface-glass))`

**Theme parity.** Dark variant computed via the same color-mix recipe
against `--ink-12` in dark.

**Drift check.** No existing token covers this — closest is `--surface-glass`
itself, which is the resting state.

New component

**Component name.** `<DialogStack>` (proposed)

**Problem.** Three places in the dashboard need to stack confirmation
dialogs (board-meeting approval flow, dissolve confirmation, settings
destructive-action stack). Every consumer is rolling their own stack
management and the focus-trap semantics drift.

**Three screens that need it.**
1. Board meeting → "Approve all consents" stacked confirmation flow
2. Settings → "Delete organisation" three-step confirmation
3. Filing dashboard → "Discard draft" with un-saved-state branch

**Minimum surface.** `<DialogStack>` with `useDialogStack()` hook. Each
dialog pushes onto the stack; Escape pops the top. Focus trap follows
the stack head.

**Why not an existing primitive.** `Dialog` from /headless handles one
dialog; stacked dialogs require coordinated focus-trap unwinding which
no current primitive does.

**API sketch.** [linked CodeSandbox or PR draft]

New variant on an existing component

**Variant name.** `<Pill tone="violet">` (proposed)

**Problem.** Three surfaces want to mark "in review by counsel" status,
and indigo is already taken for "in progress." The team has been
inlining ad-hoc colors.

**Three screens.** [as above]

**Token proposal.** Requires `--matter-violet-bg` and `--matter-violet-dk`
in `@matter/tokens`. (Token proposal in same PR.)

**Drift check.** Indigo carries a different semantic (active in-progress);
the new violet should not visually conflict — proposed hex is offset
enough to read distinct.

Review cadence

  • Bug fixes / copy edits. Direct PR, no synchronous review. Maintainer merges within 24h.
  • New variant / new prop on existing component. Async review on the PR. Maintainer responds within 48h.
  • New token / new component / pattern change. 15-minute synchronous pairing. Schedule via #design-system.
  • Voice or tone rule change. Async review with sign-off from the brand lead. The brand lead is the source of truth on voice; reach out before opening a PR.

Deprecation policy

When a token or component is removed:

  1. Mark status: deprecated in the component MDX frontmatter. The page renders a deprecation banner at the top.
  2. Document the migration target. Every deprecation MDX page must include a "Migration target" section pointing to the canonical replacement.
  3. Soft-deprecate for one minor release. The deprecated component continues to render and pass tests, but emits a console warning in dev.
  4. Remove in the next major release. The component is removed; the MDX page redirects to the migration target.

The current deprecation queue lives in apps/design/scripts/check-design-drift.ts — the gate enforces that no status: deprecated component lacks a migration-target link.

Version-bump rules

Semver, applied as you'd expect:

BumpWhat changedExamples
MajorBreaking change to any public surfaceToken rename, component removal, prop type change
MinorAdditive change to any public surfaceNew token, new component, new variant on existing component
PatchInternal change with no public-surface effectBug fix, refactor, dependency bump, doc fix

The version field in packages/tokens/package.json is the canonical version for the whole system. @matter/components and @repo/brand track it.

Breaking change checklist

Before merging a major-version bump:

  • Every consumer in apps/app, apps/web, apps/docs migrated.
  • Changelog entry includes the BREAKING tag + migration steps.
  • llms-design.txt regenerated so agents see the new shape.
  • One downstream consumer (a Matter customer or internal team) was notified before the bump merged.

Escalation paths

  • The proposal is stuck in review. Ping the maintainer in #design-system with a link to the PR. If they're not responsive within 72h, escalate to the brand lead.
  • A breaking change broke a downstream consumer. File a regression issue tagged design-system:regression. Maintainer rolls back within 24h if the regression is severe.
  • You disagree with a "no" verdict on a proposal. Open a follow-up issue describing why the bar wasn't met. Maintainer's "no" is a strong default but reversible with new evidence.

Where the rules live

RuleSource of truth
The 15-section component rubric/usage/component-page-rubric
The voice contract/usage/voice + voice.rules[] in /design-system.json
Token + component coveragecheck-design-drift.ts
Color literals are forbidden in MDXSame drift gate, invariant 4
Props introspection coverageSame drift gate, invariant 5
Token TS↔CSS paritypackages/brand/test/tokens-sync.test.ts

Every rule is enforced by a test or a build gate. Anything that isn't gated yet is a TODO — propose the gate in a PR.

On this page