Why most consistency checklists do not work
The standard list asks questions like "is the look and feel of the interface consistent?" and "are labels used consistently?". Those are restatements of the goal. The person running the audit has to convert each one into something checkable, and they will do it differently every time — which makes the audit itself inconsistent.
A check needs three things to be worth having: a specific thing to look at, a way to look at it, and a condition that decides pass or fail. Everything below has all three.
Pass one: mechanical
Five minutes, no judgement required, and it finds a surprising share of real drift. Each of these should end up in CI once it passes; a check that only runs during audits lets drift accumulate between them.
- 1
Literal colour values outside the token file
The single highest-yield check. Any hex in a component means the token layer was bypassed, and it means that colour cannot be changed centrally.
grep -rn --include='*.tsx' --include='*.css' -E '#[0-9a-fA-F]{3,8}\b' src \ | grep -v 'tokens\|globals.css' - 2
Font weights outside your band
Weight is where hierarchy silently reverts to framework defaults. If your system says 400 and 600, anything heavier is drift regardless of how it looks.
grep -rn --include='*.tsx' -E 'font-(bold|extrabold|black)|font-weight:\s*[78]00' src - 3
Spacing values off the scale
Arbitrary-value escape hatches are where the rhythm dies. One
p-[13px]is nothing; forty of them is a second spacing system nobody agreed to.grep -rn --include='*.tsx' -E '\b(p|m|gap|space)-\[[0-9]+px\]' src - 4
Radius values
Radius drifts more than anything else because every component author picks what looks right in isolation. Count the distinct values in use; more than three or four is a finding.
grep -rhoE 'rounded-[a-z0-9]+|border-radius:\s*[0-9]+px' src -r \ --include='*.tsx' --include='*.css' | sort | uniq -c | sort -rn - 5
Properties your system forbids
Whatever your prohibition list names. If it says elevation is never a shadow, this check enforces that. If you have no prohibition list, that is the finding — write one first.
grep -rn --include='*.tsx' --include='*.css' -E 'box-shadow|shadow-(sm|md|lg|xl)|gradient' src
Run these before you look at anything. Every result is a definite finding requiring no discussion, and clearing them first means the comparative pass is looking at genuine judgement calls rather than obvious misses.
The fourth check has a wrinkle worth naming: counting distinct radius values tells you about consistency, not correctness. Three values used deliberately — 6px on controls, 12px on containers, full on avatars — is a system. Three values that happen to be 6, 8 and 10 is drift that has not been noticed.
Pass two: comparative
Here is the thing every audit process gets wrong. Reviewing a screen on its own tells you whether it is internally coherent. It tells you nothing about whether it matches the other screens, because you cannot hold the other screens in your head accurately enough.
Drift is invisible per file and obvious in comparison. Per-pull-request review structurally cannot catch it.
So open three finished screens from the same surface side by side — three application screens, or three marketing pages, never a mix. Comparing a dashboard to a landing page produces differences that are supposed to be there.
| Look at | Fails when | |
|---|---|---|
| Density | Control padding, row height, gap between sections | One screen breathes and another is cramped, with no reason in the content |
| Hierarchy | How the page title is distinguished from a section title | One uses size, another uses weight, a third uses colour |
| Elevation | How a raised surface is indicated | Shadows on one screen, borders on another |
| Empty states | What happens with no data | An illustration on one, a sentence on another, nothing on the third |
| Loading | What appears while data is in flight | Skeletons, a spinner, and a blank flash across three screens |
| Error presentation | Where an error appears and what it looks like | Inline on one, a toast on another, a full-page state on a third |
The bottom three rows are where consistency work is nearly always weakest, and it is not carelessness — empty, loading and error states are written under time pressure, individually, by whoever happened to be in that file. They are also disproportionately what a frustrated user sees.
If your design system says nothing about empty, loading and error states, expect all three to differ on every screen and expect no review to catch it. These states need to be specified as explicitly as buttons are, and almost never are.
The full comparative checklist
The six rows above are where drift concentrates. This is the complete list, grouped so you can work through it in one sitting. Each item has a pass condition rather than a question.
Colour
- Every colour in every screen resolves to a named role. Fails if any component contains a literal value.
- The accent appears on the same kinds of element across screens. Fails if it is a button on one screen and a heading on another.
- Status colours appear only for status. Fails if the success colour is used decoratively anywhere.
- Every light-mode colour has a dark-mode counterpart that was chosen, not derived. Fails if any surface is a straight inversion.
Typography
- Every size on screen is a step in the scale. Fails if you find a size that is not.
- Weights stay inside the declared band. Fails on any weight above it, however good it looks.
- The same semantic level looks the same everywhere — every page title matches every other page title. Fails if two screens distinguish their title differently.
- Numbers in columns are tabular and aligned. Fails if digits do not line up between rows.
Space and shape
- Every spacing value is a scale step. Fails on any arbitrary value.
- Distinct radius values are few and each has a stated purpose. Fails if you cannot say why 8px exists alongside 6px.
- Elevation is indicated the same way everywhere. Fails if shadows and borders are both in use for the same job.
- Section rhythm is consistent — the gap between a heading and its content is the same on every screen. Fails on any variation without a reason.
Components and controls
- One implementation per component. Fails if two files define a card.
- Primary actions look identical and sit in the same relative position. Fails if one screen puts it left and another right.
- Destructive actions are visually distinct and consistently so. Fails if delete looks like save anywhere.
- Interactive elements have a visible focus state, and it is the same state everywhere. Fails on any missing or divergent focus ring.
- Disabled states are visually distinct from muted content. Fails if a user cannot tell an unavailable control from de-emphasised text.
The states nobody specifies
- Empty states use one treatment across the product. Fails on an illustration here and a sentence there.
- Loading uses one mechanism. Fails on a skeleton, a spinner and a blank flash across three screens.
- Errors appear in the same place with the same treatment. Fails on inline here, toast there.
- Error text says what went wrong and what to do. Fails on anything that only apologises.
- Long content truncates the same way everywhere. Fails if one place wraps and another ellipsises with no rule behind it.
Work through the last group first if you are short of time. It is the group most likely to fail, least likely to be specified anywhere, and most likely to be seen by a user who is already having a bad time.
Content and language
- The same concept has one name everywhere. Fails if the interface says "project" in one place and "workspace" in another for the same thing.
- Buttons name the action they perform, and the confirmation echoes it. Fails on "Submit" followed by "Your changes were saved".
- Capitalisation follows one rule for labels, headings and buttons. Fails on mixed title case and sentence case.
- Dates, times and numbers use one format. Fails on two date formats in one product.
The first item in that group causes more real user confusion than any visual inconsistency in this article. Two names for one concept means the user maintains two mental models and cannot tell whether they are the same thing.
Pass three: are the rules themselves coherent?
Once a quarter, audit the system rather than the interface. The question is not whether people followed the rules but whether the rules could be followed.
| Signal | What it means | |
|---|---|---|
| A rule with a caveat in it | "Generous spacing, though tables may be denser" | Two rules pretending to be one. A model or a person has to pick, and they pick differently |
| The same exception requested repeatedly | Three teams needed the same off-system value | The semantic layer is missing something. Promote it rather than granting exceptions |
| Component-level tokens multiplying | Many tokens with exactly one consumer | The escape hatch has become the main road |
| A rule nobody can state from memory | Everyone has to look it up | Either it is too complicated or it is arbitrary. Both are fixable |
The first row is the one to check hardest, because a hedged rule looks like a thorough rule. If your guidance has caveats in it, the surfaces those caveats describe want separate documents — governance covers the structural version of this.
What changes when an agent writes the screens
Two things, in opposite directions, and both change how you should run this checklist.
The mechanical pass becomes more important, because the volume of code has gone up and review capacity has not. An agent producing forty screens between reviews will reproduce any drift forty times before anyone looks. Automated checks are the only thing that scales with that.
The comparative pass becomes more important too, and for a subtler reason. An agent is extremely consistent *within* a file and has no memory across sessions, so its output is a set of internally-coherent screens that differ from each other. That is precisely the failure mode per-file review cannot see.
The root cause is usually upstream. We sampled 299 DESIGN.md files written to give agents design guidance: 86% specify colours as raw hex with no semantic role, 76% state no prohibitions of any kind, 69% define no dark mode, 57% name no motifs, and 44% contain no concrete size value anywhere. 54% rely on at least one vague adjective — "clean" in 39%, "modern" in 36%.
A file like that leaves the density, hierarchy, elevation and empty-state decisions unmade, so the model makes them fresh on every screen. Consistency findings against that guidance are real, and fixing them one screen at a time will not hold. How to write guidance that does.
Identity Forge design kits close that gap directly: semantic colour roles across light and dark, type and spacing scales, motifs, and an explicit do's and don'ts list, serialised into a DESIGN.md the agent reads before writing. Browse the kits.
The short version
If you have twenty minutes rather than a day:
- Grep for hex values outside the token file. Every hit is a finding.
- Grep for font weights above your band. Every hit is a finding.
- Count distinct radius values. More than four, look at why.
- Open three screens from one surface. Compare density, hierarchy, elevation.
- Look specifically at their empty, loading and error states. This is where it will be worst.
- Check whether your guidance has a prohibition list. If not, that is the fix that prevents the next round.
Steps one to three are automatable today and should never need running by hand again. Steps four and five need a person and are worth a recurring half-hour. Step six is the one that decides whether you are doing this again next quarter.
How do I audit UI consistency?
In three passes. Mechanical checks you can grep — literal colours, font weights, off-scale spacing, radius spread, forbidden properties. Then a comparative pass with three finished screens from the same surface side by side. Then, quarterly, an audit of whether the rules themselves are coherent.
Why does code review not catch design inconsistency?
Because review looks at one file, and drift only exists between files. A screen can be entirely coherent on its own and use a different density, hierarchy and elevation strategy from every other screen. You cannot hold the others in your head accurately enough to notice.
What are the most commonly inconsistent parts of an interface?
Empty states, loading states and error presentation, by a wide margin. They are written individually under time pressure, they are rarely specified in a design system, and no review process compares them — while being disproportionately what a stuck user encounters.
How often should I run a consistency audit?
Put the mechanical checks in CI so they run continuously. Do the comparative pass monthly or after any burst of new screens. Audit the rules themselves quarterly. Anything that only happens during a scheduled audit lets drift accumulate for a full cycle.
Is AI-generated UI more or less consistent?
Both, in a way that defeats normal review. It is highly consistent within a single file and has no memory between sessions, so you get a set of internally-coherent screens that differ from each other. Automated checks and screen-to-screen comparison are the two things that catch it; per-file review structurally cannot.