Dev.to AI 🤖 Ai 👁 0 📖 4 min read

Prompting for Design-System Compliance Without Dumping the Whole Library

I used to paste half the design system into the agent prompt “just so it knows our Button.” The reply was longer, slower, and somehow still invented a new PrimaryButton with a hardcoded hex. More context is not the same

I used to paste half the design system into the agent prompt “just so it knows our Button.” The reply was longer, slower, and somehow still invented a new PrimaryButton with a hardcoded hex.

More context is not the same as better compliance. Agents drown in component catalogs. What they need is a small, sharp contract: which primitives exist, which props are legal, and what “done” looks like when the diff lands.

Here’s the prompting pattern that finally stopped the reinvent-the-wheel PRs.

The failure mode: catalog dump

A prompt that looks like this fails quietly:

Here is our entire components/ui tree (paste 40 files). Build a settings form that matches the design system.

What I got back:

  • A new SettingsCard that duplicated Card
  • Inline styles next to token imports
  • A custom toggle instead of our Switch
  • “Close enough” spacing that wasn’t on the spacing scale

The model saw the library. It didn’t treat the library as the only legal surface. Catalog dumps read like inspiration boards, not constraints.

What “compliance” means in a prompt

I define compliance as four checks the agent can fail against:

  1. Import allowlist — only from @/components/ui/* (or whatever your package is), no parallel primitives
  2. Prop allowlist — use documented variants (size, tone, intent), don’t invent big / fancy
  3. Token rule — colors/spacing/radius come from tokens; no raw hex/rgb/px magic numbers in JSX
  4. Composition rule — assemble screens from existing primitives; new components need an explicit “new primitive approved” flag

If the prompt doesn’t name those four, the agent will optimize for “looks like a settings form,” not “uses our system.”

The slim context pack I actually paste

Instead of the whole library, I keep a design-system cheat sheet under ~80–120 lines and refresh it when the public API changes:

## Legal UI imports
- @/components/ui/Button — variants: primary | secondary | ghost | danger; sizes: sm | md | lg
- @/components/ui/Input — always pair with Label; error via `error` prop, not helper text hacks
- @/components/ui/Select, Switch, Checkbox, Textarea, Card, Stack, Inline, Dialog, Toast
- Forbidden: inventing Button2, PrimaryButton, CustomInput, or wrapping divs that reimplement focus rings

## Tokens
- color: bg.default, bg.subtle, fg.default, fg.muted, border.default, accent.primary
- space: 1–8 (use Stack/Inline gap; no raw margin: 13px)
- radius: sm | md | lg | full

## Composition defaults
- Forms: Stack gap={4}; actions in Inline justify="end" gap={2}
- Destructive actions: Button variant="danger" + confirm Dialog
- Empty states: Card + Stack + muted fg text — no one-off EmptyBox

## Acceptance (must pass before PR)
- [ ] Zero new files under components/ui unless ticket says “new primitive”
- [ ] Zero hex/rgb in changed files
- [ ] All interactive elements use ui/* primitives
- [ ] Story or Playwright covers the primary path

That’s the whole “library” the agent gets for most feature work. Storybook links and full prop tables live in the repo; the prompt carries the decision surface.

Prompt shape that works

My default ask looks like this:

Build X using only the Legal UI imports below.

Do not create new primitives.

If something is missing, stop and name the gap — don’t invent a component.

Match tokens and composition defaults.

When done, paste the Acceptance checklist with pass/fail.

Then I attach the cheat sheet. Short. Boring. Explicit stop rule.

The “stop and name the gap” line matters. Without it, agents fill holes with lookalikes. With it, I get a one-line question: “We don’t have a DatePicker in the allowlist — use native input type=date or open a primitive ticket?” That’s a better outcome than a 200-line custom calendar.

Give examples of illegal diffs, not just legal ones

Positive examples help. Negative ones teach the fence:

- // illegal: new parallel primitive
- export function FancyButton(...) { ... }

- // illegal: token bypass
- <div style={{ color: '#3366ff', marginTop: 13 }}>

+ // legal: compose
+ <Button variant="primary" size="md">Save</Button>
+ <Stack gap={4}>...</Stack>

I keep 3–5 illegal snippets in the cheat sheet. Agents pattern-match hard on “don’t do this” when it’s concrete.

Scope the blast radius in the prompt

Design-system compliance dies when the task is too big:

“Rebuild the billing settings page and modernize the UI.”

Too much room to invent. I split:

  1. Wire data + existing layout shells
  2. Replace one control cluster at a time (plan → payment method → invoices)
  3. Only then ask for empty/error states

Each step reuses the same cheat sheet. Compliance stays local. Reviews stay reviewable.

What I keep out of the prompt

  • Full Storybook MDX for every component
  • Internal implementation of Button (focus ring CSS, motion tokens)
  • Figma screenshots of every state (I’ll attach one screen if layout matters)
  • The entire tokens JSON

Those are retrieval problems, not prompt problems. If the agent needs a prop, it can open the type file — I point it at Button.tsx / the package exports, not paste the source.

A quick pre-merge smell check (human or bot)

Before I trust the PR:

  • rg for hex / rgb( in the diff
  • New files under components/ui without a ticket tag
  • Imports from random ../shared/Button paths
  • Class names that reimplement spacing the Stack already owns

If any of those show up, the prompt failed — or the agent ignored the stop rule. I fix the cheat sheet, not just the diff.

Takeaway

Design-system compliance is a constraint problem, not a context-window problem. Dumping the library trains the model to remix. Shipping a slim allowlist, token rules, illegal examples, and a hard “don’t invent — ask” stop rule trains it to compose.

I still review. The cheat sheet just makes “does this look like our system?” a checklist instead of a gut feel — which is the only way agent UI diffs stay boring on purpose.

📰 Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.