How to keep AI-generated React interfaces consistent
Why screens drift when a coding agent builds them one prompt at a time, and the five layers that stop it: tokens, shared components, whole screens with states, written rules and a check.
By Prodular · Published
Ask a coding agent for one screen and it will usually look fine. Ask for twenty and they stop looking like one product. A blue that is almost the brand blue. Three kinds of card. A table that pads its rows differently from the one next to it.
None of these is a bug. Each is a small design decision the agent made again, because nothing told it the decision was already made. Consistency comes from taking those decisions off the table, in five layers.
Why AI-built screens drift
An agent works from what is in its context: your prompt, the files it opened and its training. If the repo does not contain an answer to "what does a card look like here", the agent picks one. Next time, with different files open, it may pick another.
Longer prompts do not fix this. They describe the system in prose, every time, and prose leaves room. The fix is to put the answers in the repo in a form the agent cannot misread.
Layer 1: semantic tokens
Give colors, radii and spacing names that say what they are for, not what they look like. An agent that writes bg-card and text-muted-foreground cannot drift to a slightly different gray, because there is no slightly different gray to choose.
// Drifts: every screen picks its own values<div className="rounded-[10px] border border-zinc-200 bg-white p-[18px] text-zinc-500">
// Holds: the theme decides, the screen only names the role<div className="rounded-xl border bg-card p-4 text-muted-foreground">Tokens also make theming and dark mode a property of the system instead of something every screen has to remember. In Prodular UI a theme is a data-theme attribute on the root element and dark mode is a .dark class. Screens do not change.
Layer 2: one copy of each component, in the repo
If the agent cannot find a Button, it writes one. Keep components as source in the repo, one file each, where the agent will see them when it looks around. The shadcn approach does exactly this: components are copied into components/ui/ rather than hidden in a package.
Then make the rule explicit: do not hand-roll a component that exists.
Layer 3: whole screens with their states
Components are not enough. The drift between screens is mostly in composition: how a page header sits, where filters go, what an empty table says. Start the agent from a complete screen instead of a blank file.
States matter as much as layout. A screen generated from one prompt usually covers the happy path. Real products spend a lot of time in the other states: nothing yet, still loading, failed, not allowed, over the limit. Prodular UI's application blocks ship with their states, switched with a ?state= parameter or a state prop. The dashboard, for example, has empty, loading, error and no-access. The agent copies a pattern for each instead of inventing one.
Layer 4: rules written for the agent
Documentation written for people explains. Rules written for agents instruct. Compare:
The approval component helps teams review agent actions.
Route every irreversible, external or financial action through an Approval and wait for an explicit approve event before executing it. Never execute on render, on timeout or on dismiss.
The second one changes what the agent does. Write rules per component: required props, which variant for which case, what accessibility needs, what never to do. Publish them where the agent will read them: in the repo (AGENTS.md or CLAUDE.md), as plain text (llms.txt), or through an MCP server the agent can query when it needs a component.
Prodular UI ships these rules for its components in each component's docs, in llms-full.txt and through its MCP server.
Layer 5: a check after the agent writes
Rules get skipped. A check does not. Even a rough one catches most drift. This finds raw Tailwind palette colors in your app:
grep -rnE "\b(bg|text|border|ring)-(slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-[0-9]{2,3}\b" app components --include=*.tsxProdular UI's check_ui tool goes further. It reads the files the agent changed and reports raw colors instead of tokens, hand-rolled buttons, inputs and tables the kit already has, cards inside cards, icon buttons without a label, generic button labels and model output that is not marked as AI. Because it is an MCP tool, the agent can run it on its own work and fix what it finds before you review.
What to keep human
The layers above remove decisions that should only be made once. They leave the ones that need judgment: what a screen is for, which information comes first, what the copy says. Review those every time.
Checklist
- Colors, radii, shadows and spacing come from named tokens. No raw palette classes or hex values in screens.
- Every component exists once, in the repo, and the agent is told to use it.
- New screens start from a complete screen with its states.
- Rules for agents live in the repo and are written as instructions.
- Something checks the agent's code before a person does.
Prodular UI is one way to get all five at once. See what is in it, or read what matters in a design system for AI coding to compare options.