The design system is more important now than ever
Making your front end opinionated for AI-driven development
Claude Code is a powerful tool. I often tell people it operates at the level of an experienced developer, but across any programming language or platform that you want.
However, when it comes to the front end, I would struggle to describe it as senior level. It is flawless in some ways — rarely, if ever, writing JavaScript that doesn't run, with very good unit test coverage — and it's happy with React, Vue, Angular or what you throw at it; however, it often makes basic mistakes that compound over time.
If you look at a chunk of front-end code produced by Claude, it will be neat, tidy and coherent. However, it struggles with one of the most fundamental rules of programming - Don't Repeat Yourself (DRY).
For example, if you ask it to create a front-end redirect from URL x to URL y, there is a good chance it will create a hardcoded function called redirectXtoY.
An experienced developer would write a function called redirect(x,y), where you can pass in whatever you want for x and y; the function is reusable for different source and destination URLs, and so the function is DRY.
I've seen this behaviour all the way up to Claude Opus 4.8, and if you are not monitoring what the model produces, these kinds of inefficiencies will pile up, creating a slow, bloated mess of a website that becomes increasingly challenging to work on until you give up. Any vibe coders out there familiar with this experience?
The Struggle
The reason these models struggle so much with front-end is that with HTML, CSS and JS, there is often no "right" way to implement something. Instead, there are hundreds of alternatives, some of which are terrible, some great, with many that are perfectly acceptable in between.
Backend code is typically a lot more opinionated. With a platform like Laravel, there is a "proper" way to implement a queue, or to set up authentication. As such, the path for a tool like Claude is clear - it follows this "proper" approach to the letter, and the result is well-written, documented and tested code.
The subtleties of what makes a good front-end solution are nuanced, and so Claude will often take the easiest path, because the best path isn't clearly laid out.
The result is that it will often abandon DRY coding principles and start hand-rolling elements inline.
Claude loves a hand-rolled pill. By default, it will create all sorts of random variations throughout your app. The solution to this is to give Claude a clear path and direction for how you want your front-end code to be produced. This is where the design system comes in.
The Design System (DS)
Design systems have been around for years. Think of them as an extension of your brand guidelines, but governing your digital presence. It is a document that renders fonts, headings, button styles, form elements and more in a clear, repeatable and structured manner.
It makes up the building blocks of your application. My colleague Russ gives a great explanation of what a DS is in his article on how they are central to product delivery.
In order for a DS to be useful in AI-driven development, it ideally needs to be part of the application itself. It should be rendered under a protected URL - /design-system - or something similar, and it should be built on the same framework, such as React or Vue, for example.
Each element rendered in the DS should be built as a reusable component, which can then be dropped into the app wherever required. Any tweaks or changes to a component should be made in the DS only, with changes cascading throughout the app from there.
For complex elements, or components that might not be immediately visible, such as modals (pop-ups), the DS should surface an interface where you can quickly cycle through the various states of the element or trigger the appropriate modal.
Your DS should ideally follow the hierarchy laid out in Brad Frost's classic book, Atomic Design (which you can read online here). This methodology breaks a DS down into five distinct levels:
1. Atoms - The smallest building blocks; a button, an input, an avatar. These are the foundational units.
2. Molecules - A few atoms bonded into a small unit that does one job. Atoms → combined.
3. Organisms - Molecules joined into a distinct section of an interface. Molecules → grouped.
4. Templates - Organisms arranged into a page skeleton; placeholder content only. Organisms → arranged.
5. Pages - A template filled with real content; the real test of the design. Templates → populated.
Following this hierarchy when creating your design system promotes a clean, elegant structure for your wider application.
Make your front end opinionated
The solution to the struggle of building front-end interfaces with AI is to make your front end opinionated.
A good DS provides the core foundations for this idea, but you need to implement your DS in a specific way and combine it with a rigid set of rules for Claude to follow. You also need to follow what Claude is doing, keeping on the right path along the way.
When building your DS, follow these guidelines:
Build it within your application, using the same front-end framework
Make it available to any developer under the url
/design-system(restrict in production)Build up the DS using fully functional, front-end components
Ensure each component has extensive unit tests, and is surfaced in a manner that all states can be exercised (e.g. for a modal, surface a button for each version of the modal so that the user can review it)
The components within your DS will then be rolled out across your website / application
Building a DS in this way will give Claude an accessible, clear framework for building and using components.
To ensure that Claude uses the DS effectively, you need to give it a set of rules to work within. At a high level, these should look something like this:
Never hand-roll any front-end code
Every component has to be in the DS
If you need an element that is not in the DS, create it in the DS first
If you need to update an element, update it in the DS
Whenever the DS is updated, pause and await sign-off on the changes
For a new feature, work on the front-end first, then the back-end
Use Claude to flesh out these rules and adapt them to your own workflow, then save them down to your CLAUDE.md file as strict guidelines.
Building the thing
So how do you put this into practice? It's straightforward, but you do need to work in a specific way.
Firstly, spin up your site using your front-end framework of choice - I use almost exclusively Vue and Tailwind (a questionable choice, as Tailwind promotes hand-rolling, more on that in a future article) - but you can choose whatever framework you like, even vanilla CSS and JS, as long as you have some sort of component layer that you can use.
From there, start piecing together your DS. Build, review and test each atom, each molecule, each organism individually, working with Claude to refine and stabilise it.
Once you have enough DS elements to start building out the app's features, go for it. Claude will pull your components together into something that hangs together well, primarily because the design decisions were made, implemented and reviewed in the DS, outside the context of the application's requirements. And if it comes across a state or an element that isn't captured in the DS, it should switch back to DS mode, update the DS, then ask for your approval before getting back to the app.
However, you do need to monitor what it's doing; unmonitored, even the most powerful models will still sometimes start ignoring your rules and hand-rolling elements. It's so tempting for the model to take a shortcut and knock out a quick hand-rolled pill!
One thing you should always try to ensure the model does is build out the front-end components first, before the back-end build. Often in the model's plan it will build the back-end first, even though the rules state otherwise. This is because that is often the easy bit with the clear solution. As such, it will typically get the backend right first time, but then it will bring all of that contextual data into the front-end build, diluting the context with unnecessary bloat, further increasing the risk of it failing the front-end task. Always instruct the model to build the front-end components first, in the DS, then pause, sign off and compact before wiring up the backend.
In summary
If you are reading this article, then you have probably experienced the frustrations of trying to build decent front-end interfaces. Introducing a design system and some well-crafted CLAUDE.md rules into your workflow can transform the outcome; however, you do still need to keep an eye on what the agent is doing.
In my next article, I'll be talking about how using a DS in this way can streamline the way that designers and developers work together on a project, which has delivered real efficiencies in how we manage our work.
Related content
Building things with AI
Our research and experiments into what AI can and can't do when it comes to building things.
The future of UX & design
Our take on the direction of travel in the UX and design industry.