A design system consistency audit compares the interface a team ships with the components, tokens, and patterns it has agreed to use. The deliverable should be a prioritized list of evidenced differences, with an owner and a disposition for each one.
Start with one important journey, such as creating a project and inviting a teammate. Include the pages, dialogs, forms, and feedback states along that journey. This gives the first audit a boundary you can finish and a workflow against which to validate changes.
The method below is a proposed audit workflow. Its example findings illustrate decisions to make; they are not measurements from a customer codebase.
1. Establish what counts as the system
Identify the approved component source, token definitions, and documentation. Record which source decides a disagreement. If the design file shows a retired button while current production and the maintained component agree, “match the design file” needs a decision from an owner.
Tokens can carry a name, value, type, and description, and can reference other tokens. The Design Tokens Community Group format formalizes an exchange format for this information. An audit can use an existing token setup without requiring migration to that format.
Write down the roles you intend to compare: primary action, secondary action, body text, muted text, page heading, panel surface, and destructive feedback. A comparison becomes more useful when it asks whether two elements have the same job.
2. Build an inventory around repeated decisions
For the selected journey, collect component imports and variants, repeated local implementations, typography roles, semantic color usage, and state coverage. Pair source locations with screenshots when available.
Use a compact inventory such as this:
| Area | Intended pattern | Observed implementation | Evidence to collect |
|---|---|---|---|
| Invite action | Shared primary Button | Local button markup | API comparison and pending state |
| Supporting text | Muted foreground token | Literal color value | Computed color in both themes |
| Page heading | Established heading role | New text size | Equivalent page comparison |
| Failed invitation | Shared inline error pattern | Generic toast only | Reproduction after server failure |
Treat these as candidate findings. A local wrapper may add useful domain behavior while still using the approved primitive. A literal color may be an external brand requirement. Both need inspection before classification.
3. Compare semantics before comparing raw values
Two elements can look identical today and still follow different rules. One may use a semantic foreground token while the other hardcodes the token's current value. Conversely, two different values may be intentional because they serve different roles.
In shadcn/ui, semantic variables pair backgrounds with corresponding foregrounds and support theme-specific values. The official theming documentation provides a concrete example of this model.
For each candidate, ask: what role is this value expressing, where is that role defined, and what should happen when the theme changes? This turns “too many shades of gray” into a fix the maintainer can evaluate.
Do not call a low-contrast shared token correct merely because it is shared. Text contrast needs its own check; WCAG defines different minimum contrast requirements for ordinary and large text, with specified exceptions. W3C's Contrast Minimum guidance explains the requirements and their scope.
4. Audit states of the real component
Review a component in the conditions that reveal its contract: a long label, pending work, disabled access, an error, narrow space, and each supported theme. Select states relevant to that component instead of creating every possible combination.
Storybook stories capture rendered component states, and args supply component inputs. This can make an existing story collection a useful audit inventory. Storybook's writing-stories documentation explains that structure.
If the team does not use Storybook, use an existing component preview or a controlled application fixture. Keep the actual component under review. A separately drawn lookalike cannot establish whether changing the shared implementation preserves its consumers.
5. Record exceptions as decisions
Give every confirmed difference one disposition: fix it, approve an exception, propose a system change, or investigate missing evidence.
An exception register can be small:
| Field | Example entry |
|---|---|
| Surface | Customer brand preview |
| Difference | Uses a customer-supplied accent color |
| Reason | The feature previews that customer's branding |
| Boundary | Preview area only; surrounding controls use product tokens |
| Owner | Feature maintainer |
| Revisit trigger | Theme editor redesign |
Prefer a specific boundary and revisit trigger to “approved for now.” When the same exception appears in several independent features, ask whether it should become an explicit system variant.
6. Prioritize by consequence and reach
For the first repair batch, select findings with a demonstrated user consequence or a repeated pattern across the audited journey. A hidden primary action deserves attention before a barely different decorative radius.
Record the component's reach before changing it. A shared primitive needs representative consumer checks; a local style may allow a smaller correction. Choose a few changes whose outcomes can be reviewed clearly instead of mixing a broad token migration with a feature release.
For each finding, include the route, state, source location, expected pattern, observed difference, proposed change, and verification needed. Mark source-based inferences separately from behavior reproduced in the rendered interface.
7. Keep drift from returning
After repairs, add the approved rule where authors and reviewers will encounter it: component documentation, examples, or the pull request checklist. Link to the correct component and state when possible.
For AI-assisted work, context and discovery belong upstream. Why agents invent components covers that problem; a private component registry can make approved options easier to find.
Track confirmed recurrence within a stated scope, rather than treating the raw number of search matches as a quality score. A useful follow-up question is whether another PR reintroduced the same rejected button variant after the rule became available.
Design Bug Bot reviews changes against repository components and styling patterns, offering findings and suggested code as another input to ongoing consistency review.
Frequently asked
- How often should a design system audit run?
- Tie it to a useful event: a substantial UI release, a theme migration, repeated review findings, or the addition of a major product area. Use ongoing PR review for the smaller changes between audits.
- Should the audit remove every duplicate component?
- First compare responsibilities and supported states. Consolidate implementations that should share a contract; preserve or document differences with a clear product reason.