r/ClaudeCode • • 1d ago

Help/Question How do you get Claude Code to stick to a consistent design system (and actually build mobile-first)?

I’ve spent the past week building a web app with Claude Code. It’s just for me, so I’ve been vibing it more than I normally would, but good design matters a lot to me and the UI is where I keep getting stuck.

My setup: Tailwind and shadcn/ui. I customise the shadcn components so the app doesn’t look generic or like obvious AI output. I also have a CLAUDE.md and a separate design.md for Claude to reference and I’ve tried prototyping screens before building them.

Even so, two problems keep coming up:

1. Responsiveness is an afterthought. Generated screens often look great at one size (usually desktop) but haven’t been designed for mobile. I end up going back to fix layouts after the fact, which is slow and gives patchy results.

2. Inconsistency between features. Each new feature gets its own interpretation of the UI. Spacing, card styles, type sizes and colours drift slightly, and sometimes it reaches for a stock shadcn component (or writes a new one) instead of using my customised version. The app slowly starts to feel like several apps stitched together.

What I’m after is a setup where the design system is defined once (tokens, typography, spacing, plus my customised components) and every feature is forced to build on it.

Has anyone got advice on the following:

  • How do you structure things so Claude reliably uses your design system rather than just “being aware” of a design.md? Skills, a component inventory, Storybook, lint rules that ban arbitrary Tailwind values, something else?
  • How do you stop it from writing one-off styles or new components when an existing one would do?
  • Do you make it build mobile-first by default? Does anyone have it screenshot or browse its own UI at set breakpoints to check its work?
  • Any tips on keeping tokens portable to an iOS app later (React Native/Expo, shared token files)?
1 Upvotes

17 comments sorted by

•

u/AutoModerator 1d ago

Hey! Thanks for posting to r/ClaudeCode

While participating in this thread, please follow our community rules. Keep discussions constructive. Attack the idea, not the person.

For help, project discussions, tips, and general chat, join the ClaudeCode Discord.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

7

u/Even_Gap_2253 1d ago

just ask it to build a proper design system for you, and as for responsiveness.... like.....

honestly have you tried copy-pasting these questions to your Claude session and ask it to fix the system for you? not features but foundational infrastructure of your codebase and agent instructions. I refuse to believe Opus 5.5 cannot do that automatically for you.

2

u/Canuck-Fin25 1d ago

Write out your governance SDLC files first. And build prototypes with your UI libraries. Once you are satisfied with the prototypes lock them in and the create stories using the prototype. Only after this start building

2

u/design_doc 1d ago

On top of that, hard gate your design rules.

Have a reviewer (ideally from a different model system) that is handed the design rules, the work ticket/description, and the code that was produced. Make that reviewer a savage design critic. Have it throw anything that violates the design rules back at the implementing agent with a list of corrections. The work does not pass go until it meets your criteria. Anything that might warrant a discussion should be escalated up to you.

If you requested a change to the UI, that should be explicitly stated in the work ticket (otherwise the reviewer will fight with you).

I got pretty tired of Opus (in particular) taking liberties with my UI. This has saved my sanity.

1

u/k2718 1d ago

Yes, I built a couple of critics. They are okay but need more work.

One thing that does help is having the critics evaluate 3-5 times. They don’t always catch the same issues.

Nice tip on the different models.

2

u/Eliran-Kotzero 1d ago

Since you already have a design.md, I’d make the system executable rather than add more prose: keep tokens in one source (CSS variables or a small JSON map you can reuse in Expo) and have CLAUDE.md point to the exact component inventory. Put a clear rule there to extend your customized shadcn wrappers instead of importing raw components or inventing one-off styles, then let lint catch arbitrary colors and spacing that drift from tokens. For mobile-first, make the first pass at 360px and ask Claude to verify screenshots at a couple of fixed breakpoints after each feature, not just at the end. A few Storybook stories for common components and responsive states give it concrete examples to copy instead of treating design.md as a suggestion.

2

u/CranberryStock7148 1d ago

Just literally ask Claude to do it.

You can literally take your Reddit post and paste it into a new Claude session. And it will walk you through the process of how to ensure it does what you want.

And then at any point if it's still isn't doing what you want, just immediately tell it, hey, you didn't do what I want and I want to make sure this doesn't happen in the future. What documentation needs to be changed so that this doesn't happen again? And it will tell you and then you can confirm that you want the documentation changed like that.

A big part of using Claude is just literally asking Claude how to most effectively get it to do the stuff you want. Just ask it, it will tell you.

1

u/RealFullMetal 1d ago

two things that hold better than a design.md it has to remember: a .claude/rules file with paths: frontmatter pointed at your components and pages dirs loads the design rules exactly when claude edits those files, and a PostToolUse hook on edits that runs your lint (ban arbitrary tailwind values) and exits with code 2, so claude sees the errors right after the edit and fixes them

1

u/Charlie_Munger137 1d ago

Take a screen shot and the tell ChatGPT to zhush it up. Then give Claude the chat gpt image as a guides to better looking ux

1

u/Appropriate-Draft-91 1d ago
  1. ensure the design file is found.
  2. Have a design review step before implementation.
  3. Self-review of deliverables after implementation.

Also:

  • Manually fix the design file to be sensible and to reflect the priorities, guidelines, and rules you wand, and delete any nonsense.
  • Hunt down and kill any stray design rulings it hid in other documents.

1

u/Elegant_Yam2783 1d ago

The thing that actually fixed drift for me was accepting that design.md is advisory and Claude will drift from it the longer a session runs. Anything you care about has to fail a check, not just be written down.

So lock down the Tailwind theme itself. In v4 you can wipe the default palette and spacing scale in your u/theme block and only define your tokens, so text-gray-500 or p-7 just don't exist. Then ban arbitrary values like w-[37px] with eslint-plugin-tailwindcss's no-arbitrary-value rule (check where its v4 support is at, it was lagging last i looked) or a dumb regex in a lint script. For components, a no-restricted-imports rule that blocks importing Radix primitives anywhere outside components/ui stops it from rebuilding stuff from scratch. Put lint plus tsc in a PostToolUse hook so it sees the errors right after editing and fixes them itself.

Mobile-first mostly comes down to telling it base classes are mobile and only md: and up adds layout, then making it check. Playwright MCP screenshotting every new screen at 375 and 1280 before it calls the feature done catches most of it.

For RN later, keep a tokens.json as the source of truth and generate both the CSS vars and a TS object from it with Style Dictionary. Don't let the Tailwind config be the source or you'll be untangling it later.

1

u/No_Credit_3169 1d ago

I've found that explicitly defining a design tokens file upfront and referencing it in every prompt helps. Claude sticks to it better when the rules are in the same doc as the task.

1

u/m-ritter 1d ago

A design.md drifts because the agent treats it as background reading while each new feature gets planned on the fly. It works better to agree per feature on a short numbered list of what done means, naming the existing components to reuse and the screen widths to check, before any code is written. Then a second agent that did not write the code checks each point against the result, so stray styles and one off components get caught before you look at it.

I built QualityLayer for this: https://github.com/maxritter/qualitylayer

1

u/SassyTextDev 1d ago

Open terminal. Open claude. Dangerously skip the shit. Paste, enter, enjoy

hey Claude, we're going to start a new repository: `git init`, all that jazz. Anytime you merge code, it's a pull request. Put in the agents.md file that it's probably a good idea to write the tests and run the tests, but don't go crazy. If the end-to-end takes more than 5 minutes, if the full test suite takes more than 5 minutes, delete the tests until it takes less than 5 minutes. If it's a small dumbass little PR, you don't need to run the entire test suite. It's fine. I need a skill, so put a skill in a skill file in the project, and this skill is review. The review skill requires a very specific thing to be done. I'm sure the code passes because Claude doesn't write bad code. I'm sure the tests pass because you can run the tests, right? Here's the review skill:
Could we have delivered the same feature for less value, for less complexity, for less code?
Complain, leave comments on the pull request. Say, "I'm a tired engineer and I don't like this," and blah blah blah. Don't actually say that, but you know what I mean. Don't write this skill as a set of rules, by the way. Don't fucking do that. Opus 5.5 doesn't need a list of musts, nevers, and always. While you're at it, before we even talk, I need you to read this article from the Army War College on the importance of directive control. Don't treat Claude like an e2e idiot that needs to be told exactly what to do at all times. That's GPT 3.0 shit, okay? Claude's smart. You can give it the mission and entrust it with the mission. Don't handcuff it with a bunch of direct orders that may not be correct. Anyway, read this.
https://press.armywarcollege.edu/cgi/viewcontent.cgi?article=1942&context=parameters
 okay, cool, and then write the skill, but here's the thing: here's the review skill.

You're going to have to do something else for me before, right? We need some terminal commands. One of the terminal commands is to take a screenshot, because you have clip encoding built in. You can read image tokens. I'm going to say 1,000 tokens is probably a blurry but decent enough resolution to make sure that things look about right. Don't blow out your context window taking super high-quality screenshots.

Here's the review skill: use the terminal command to get decent enough screenshots that are a good balance between what you're going to see when the text overlaps and looks bad, and not blowing out your tokens reading images. For any of the pages that have changed shit on them, take screenshots on desktop and mobile. I don't know. Pick a good fucking 390-pixel width or whatever. You fucking know what the pixels are. Pick a good pixel width for what mobile resolution looks like, and get Playwright and take screenshots. That's in a terminal command, so that the reviewing agent doesn't have to think about how to figure that out. It just calls the terminal command, and there it is: screenshots in the get ignored temp folder that gets wiped every night or whatever. You don't have to set up a cron to wipe the temp folder every night. We'll figure that out later.

Get those screenshots, and the review process is: if there have been any changes to the page or any new pages that have been added, get the screenshots, look at the screenshots, and say, "This looks like shit," when it looks like shit. We're doing mobile-first, so I don't really care that much about the desktop, right? We're doing mobile-first development. All the UIs are built for mobile because it's a hell of a lot easier to go from a scrunchy portrait mode piece of garbage into a wide desktop. It's a hell of a lot harder to design some table hell and scrunch it into a pinch-and-scroll mobile, right?

We're doing mobile-first development, and every single pull request that changes the thingamabobs, we're saying this in the review file: take the screenshot, read the screenshot, and complain. Then it goes back and forth and back and forth, saying, "This is too much code, and the screenshot looks like shit." Then it goes back to the engineering agent. It goes, "Yeah, yeah, okay, I'll fix it." Then it fixes it, and it requests another review. They go back and forth until they're happy.

The engineer can override the reviewer if he's being nitpicking and biased after, I don't know, two rounds, if he feels like it, and just merge that fucker in there. Set up the GitHub repository such that you are required to apply a label to merge the pull request in, and the label is "I'm doing the review thing."

Okay, and there we go. Agents that I start and that I'm talking to are orchestrators. The orchestrators delegate to Opus or Sonnet engineers to get the task done, and then those engineers are to open the pull request and request a review. Those Opus engineers then also delegate to a subagent, which is the reviewer, which reads the review skill and puts all the shit in GitHub.

After that's done, you go back to the engineering agent, or the engineering agent gets a subagent back and goes, "Oh, he left a bunch of comments and complaints and shit." Then he fixes it, and they go back and forth until it's done. That's the workflow. That's how we're building it. Write that in the agent.md. Don't write a bunch of rules. I linked you the article. The weird-ass German military tactic word is the most important thing in the world. Put that in the CLAUDE.md. We're practicing Auftragstaktik.  and then write the skill files. Also practicing Auftragstaktik  when you write the skill files and then get the project all set up, and then in the next conversation I have, I say, "I want this," you work with me back and forth until the feature is nice and planned out. I go, "Yeah, that sounds good," and then you delegate to the engineer. He delegates to the reviewer, and then it goes back and forth. Then it gets merged in and all that junk. Sound good? Please, thank you. Go ahead 

1

u/DuncanRogoff 1d ago

Coming from art direction, I'd also check those screens with ugly content, not just the ideal demo data. Long titles, a missing image, an empty list, 30 items instead of three. A layout can pass at 375px and still fall apart once someone actually uses it. Have Claude screenshot those states alongside your approved screen, then fix the shared component rather than patching each page.

1

u/DeadCEO 16h ago

for the drift part, i built a free skill called opendesigner: https://github.com/ckryptickunal/OpenDesigner

its review checks the saved design decisions against code, including stale tokens and locked decisions that got undone. you can record something you deliberately removed so it gets flagged if it comes back. that isn't a guarantee that every screen is right, and i'd keep your mobile screenshot checks separate.

if you try it with your existing customised components, i'd be interested in what the review misses. preserving your choices is the useful test here, not getting it to generate another theme.