DEV Community

思源
思源

Posted on

How to make Claude Code build new pages that match your existing app

Ask Claude Code to "add a pricing page" to a project that already has ten pages, and you often get a beautiful page that belongs to a different website. New font pairing, a fresh accent color, a hand-rolled button, maybe its own <style> block. On a new project that's great. In an old project it's a clash you now have to undo by hand.

I hit this enough times across my own side projects (a resume builder and a small Next.js app for checking product ideas) that I stopped fixing pages after the fact and started fixing the instructions instead. This post is the loop I use now, with the prompts and grep commands. Nothing here needs a special tool — it's a SKILL.md file plus a habit.

Why it happens

Most frontend/design skills are written to make output distinctive. The official frontend-design skill in anthropics/skills, for example, pushes for bold, non-generic choices. That's the right goal when there is no existing design. But the model reads the skill, not your codebase, so "be distinctive" wins over "look like the page next door".

The fix is to reverse the order: read the project first, write a short summary of its style, build only from what already exists, then check.

Step 1: Give the agent a design source of truth (if you have one)

In my resume builder repo, the root AGENTS.md has a short rule:

Before changing the visual or interaction layer of `resume-tailor/`,
read `resume-tailor/docs/design-system.md` first. Colors, type scale,
radius, buttons, cards, forms, motion, i18n copy and page skeletons
each have exactly one correct way to write them there.
Enter fullscreen mode Exit fullscreen mode

The design doc itself was not written as an ideal. It was written by measuring the existing code: which tokens are defined in globals.css, how often each className appears, which components are actually imported. That surfaced uncomfortable facts — at one point the codebase had 49 different hand-written button styles while the shared components/ui/button.tsx was imported zero times.

A few things that made the doc genuinely useful for an agent, not just for humans:

  • List the theme-aware class names explicitly. e.g. bg-background, text-foreground, bg-card, bg-muted, text-muted-foreground, border-border. "Use tokens" is vague; a list of allowed names isn't.
  • Write down the exceptions and why. Hard-coded palette classes are allowed in exactly three cases (dark sections, data signal colors, the rendered resume paper). Everything else goes through tokens. After one cleanup pass, hard-coded colors went from roughly 2,370 occurrences to 115, all of them in those exception buckets.
  • Record the traps. In that project rounded-xl and rounded-2xl both resolve to 16px because --radius is recalculated, and a gradient-text class silently disappears if you wrap the text in an extra <span>. Those are exactly the details a model gets wrong.

If you don't have a design doc, don't write one first. Step 2 works without it.

Step 2: Make the agent survey before it writes

This is the core of the skill I wrote, match-existing-style. The first section is a reading list, and it says "do not skip":

## 1. Survey before you design (do not skip)

1. Design rules — any DESIGN.md, design-system.md, docs/design*,
   or a design section in AGENTS.md / CLAUDE.md / README.
   If one exists, it wins over everything below.
2. Tokens — CSS variables (:root, @theme), tailwind.config.*,
   theme files. Note the token NAMES, not just values.
3. Component kit — components/ui/* or similar. Which primitives
   exist (Button, Card, Input, Badge, Dialog…) and how they're imported.
4. Two sibling pages — the existing pages closest to what you are
   building. Note container width, section spacing, heading sizes,
   card style, how the hero is built.
5. Copy voice — languages, i18n helper, sentence vs title case.
Enter fullscreen mode Exit fullscreen mode

"Two sibling pages" is the part that does the heavy lifting when there's no documentation. Your existing pages are the design system; the agent just has to open them.

Step 3: Force a style fingerprint before any code

Next, the skill asks for 8–12 lines of summary before touching a file:

## 2. Write a style fingerprint (keep it short)

- Colors: token names for background / surface / text / muted /
  border / primary action.
- Type: font families in use (do not add new ones), heading sizes
  on sibling pages, body size.
- Shape: radius per element type, shadow style, border usage.
- Spacing rhythm: page container, section gaps, card padding.
- Components: which primitives you'll reuse for each part of the page.
- Patterns to copy: one concrete snippet from a sibling page to mirror.
- Copy: language handling and tone.
Enter fullscreen mode Exit fullscreen mode

Two reasons this matters. First, writing it down commits the model to specific token names before it starts generating JSX, which is when drift happens. Second, you can read 10 lines and catch a wrong assumption in seconds, which is far cheaper than reviewing a 400-line page.

Step 4: Build by reuse, with hard "no"s

## 3. Build by reuse

- Reuse before you write. Use the project's Button/Card/Input.
- Tokens, not values. No raw hex/rgb or arbitrary palette classes
  unless sibling pages do the same thing for the same purpose.
- No new fonts, no new accent colors, no new radius scale,
  no new shadow style.
- Match the page skeleton of the nearest sibling.
- Missing piece? Build it in the project's idiom and say so.
  Do not pull in a new UI library.
Enter fullscreen mode Exit fullscreen mode

The "say so" line is important. When the page genuinely needs something that doesn't exist yet, you want to hear about it in the summary, not discover a new dependency in package.json later.

Step 5: Self-check with grep, not vibes

The last step is mechanical. Run these against the files the agent created:

# raw colors
grep -nE '#[0-9a-fA-F]{3,8}\b|rgb\(|hsl\(' app/new-page/page.tsx

# raw palette classes the sibling pages don't use
grep -nE '\b(bg|text|border)-(slate|gray|zinc|indigo|blue)-[0-9]+' app/new-page/page.tsx

# hand-made buttons instead of the project's Button
grep -n '<button' app/new-page/page.tsx

# new font imports
grep -n 'next/font' app/new-page/page.tsx
Enter fullscreen mode Exit fullscreen mode

Then, if you can render it, screenshot the new page next to a sibling page. A side-by-side picture catches things no grep will: a different hero height, a missing site header, a card that's slightly too round.

Does it actually make a difference?

I ran a small test: same project, same prompt, two subagents in separate git worktrees. One followed the official frontend-design skill, the other followed match-existing-style. Each built the same new page.

Round 1 was the resume builder, which has a design doc. Round 2 was the idea-checking app, which has no design docs at all — only globals.css tokens and components/ui.

Generic design skill match-existing-style
Hard-coded hex colors (round 1 / round 2) 17 / 30 0 / 0
New fonts added 2 / 2 0 / 0
Project token classes used 0 / 0 19 / 34
Own <style> block 1 / 1 0 / 0

In round 2 the generic-skill page also dropped the site's header (logo, language switch, sign-in) entirely, and came in at 499 lines versus 247.

To be fair to the official skill: its page was well made. It was just aiming at a different goal. And this is one run per project, two projects — a small sample. But the direction held even without a design doc, which was the case I was most unsure about.

The short version

If you only take one thing from this, paste something like this before your next UI request:

Before writing any code: read our design rules (if any), our CSS
tokens, components/ui, and the two existing pages most similar to
what I'm asking for. Write a 10-line style fingerprint (token names,
fonts, radius, spacing, components to reuse, one snippet to mirror).
Then build using only those. No new fonts, colors, or button styles.
When done, grep your new files for hex colors, raw palette classes
and <button>, and list every deviation from the existing style.
Enter fullscreen mode Exit fullscreen mode

I'm packaging the full version as a Claude Code skill — the survey/fingerprint/reuse/check loop plus recipes for the pages people add most (forms, settings, data tables, pricing, empty states). It's in early access here if you want it: Match Style.

Top comments (1)

Collapse
 
navedux profile image
Naved Alam •

The style fingerprint before writing code is a useful step. I ran into a similar problem with illustrations: the agent would drift from the existing style, and I'd have to teach it again. That's why I built illos.dev, animated SVG illustrations plus skills for drawing new ones in the same theme. Different surface, same consistency problem. How reliable has the final drift check been for you, especially for differences that are hard to catch with grep?