shadcn/lint: Design Rules Agents Can Check
September 15, 2026•6 min read
I saw this tweet from shadcn about shadcn/lint:
Introducing shadcn/lint. An agent-first linter for Tailwind design systems.
You define what’s allowed. When an agent breaks a rule, the error explains what’s wrong and how to fix it using your components, variants and theme.
There’s a lot you can do with this. Let me show you ↓
It reminded me of what I liked about StyleX: making design rules part of the code.
If a button is in my component library, I expect the agent to use it. That should be the default.
But using the component does not mean using it correctly. The agent can still add its own padding or change the background color. Then someone needs to explain why it should use an existing size or variant.
What I like about this tool is that you can put that explanation in the lint error. The agent gets the rule and some help with the correction when it checks its work.
That makes a lot of sense to me. If we already know what the agent should use, why leave that explanation for code review?
Using the component is only the first step
Imagine a project with a shared Button component. Its size option controls padding, text size,
and height together.
An agent writes this:
<Button className="px-7 py-5">Create project</Button>The agent uses the right component, but changes part of its appearance directly. Now this button has spacing that the shared component does not define.
One change looks harmless. Repeat it across several pages, and the interface becomes harder to maintain. Updating the shared button may no longer update every button as expected.
The component library already provides the button and its size options. The check needs to enforce how the agent uses them. Internal spacing belongs to the button's size options.
How shadcn/lint works
The package works with Tailwind v4 and supports ESLint and Oxlint. It also works with components outside shadcn/ui. The project documentation explains how to identify your component imports and theme.
You select rules and define what each component permits. The linter checks the code and reports violations with guidance. The agent then edits the code and runs the check again.
The no-restyle rule controls classes passed to recognized design-system components. A component
contract gives one component its own policy. Here is an example rule entry for an existing setup:
'shadcn/no-restyle': [
'error',
{
allow: ['layout'],
contracts: [
{
pattern: '^Button$',
allow: ['w-full', 'mt-*', 'mb-*'],
message: {
spacing: 'Choose a defined Button size. Check the component before adding another size.',
},
},
],
},
],This button contract permits full width and vertical margins. It rejects the padding classes in the earlier example. The custom message explains the next step.
If this project's button defines size="lg", the agent can use it:
<Button size="lg" className="mt-6 w-full">
Create project
</Button>The page controls placement. The button controls its internal spacing. The no-restyle documentation describes these contracts and custom messages.
The example is only a rule entry. Follow the
setup guide to register the plugin and
configure your parser. Disable no-restyle inside the component implementation directory so
components can define their own appearance.
The error becomes part of the instruction
The part I find most useful is the guidance after a failure.
A rejection tells the agent that its current answer is wrong. A useful error also gives it a path to an acceptable answer. That can reduce the need to guess again.
The tool supports messages with component names, available variants, and file paths. Here, a variant means a named component option, such as a size. See the message options for the available values.
For me, this makes the rule easier to act on. The agent receives the relevant instruction at the place where it needs a correction. People who join the project get the same help.
The process stays simple:
- The agent changes the interface code.
- It runs the lint command.
- It reads the reported problems and guidance.
- It corrects the code and runs the command again.
The team still needs to require that command. A check only helps when the development process runs it.
Why I think this is a good idea
A rule becomes more useful when the project can check it.
Written guidelines explain intent, examples, and exceptions. Automated checks can enforce the parts that the team expresses precisely. Together, they make the expected result clearer.
I also see a benefit for code review. Reviewers can spend less attention on repeated spacing corrections when a check already catches them. They can spend more attention on whether the interface solves the user's problem.
Another benefit is consistency between contributors. A person and an agent receive the same rule from the same project configuration. The standard does not depend on who remembers a previous review comment.
These are reasons I find the approach promising. They are not measurements from using it in my own projects.
What a passing check cannot tell you
A page can follow every configured rule and still be confusing. The team still needs to review its content, accessibility, behavior, and appearance at different screen sizes.
The checks also have technical limits. For example, no-restyle checks recognized components and
does not inspect the CSS behind custom classes. The
documented limits
explain where other checks are necessary.
Rules also need maintenance. A repeated failure may reveal a missing component option or an unnecessarily strict policy. The team needs to decide whether the implementation or the rule needs to change.
I would start with a few recurring mistakes from real reviews. Each rule needs a clear reason and a useful correction. Then I would expand the rules as the team learns what helps.
What I take from this
Two weeks ago, I explored typed styling contracts in StyleX. Both approaches make design systems stronger by turning customization rules into checks.
StyleX puts those rules in the types a component exposes. shadcn/lint configures checks for Tailwind usage and provides correction guidance. They suit different setups, but both make the team's decisions easier to apply.
shadcn/lint gives a concrete form to an idea I like: make project expectations testable and make failures useful.
For agents, that creates a clearer path to an interface that fits the product. The quality of that path depends on the rules and guidance the team provides.
Which design rule would you automate first? Share it with me on X.