Adding linting to an existing project
September 14, 2026 ยท View on GitHub
Start with one rule. Fix the common violations, then add more checks. You can set each rule's severity and choose which files it checks.
Use the README setup first. The examples below use ESLint; keep its plugin and parser configuration. Oxlint supports the same rule settings and file overrides.
Start with warnings
Set no-restyle to warn in the main rules object:
"shadcn/no-restyle": ["warn", { allow: ["layout"] }]
This keeps layout classes allowed, as in the README. Keep the component-directory override, then run:
npx eslint .
With Oxlint, run npx oxlint.
Look for repeated errors, such as padding on buttons. Fix those patterns before working through individual files.
Limit the warning count
Use the measured count in your lint script. For example, if the project has 287 warnings:
{
"scripts": {
"lint": "eslint . --max-warnings 287"
}
}
Run this script in CI. It fails when the total increases. Lower the cap as you fix findings. Oxlint supports the same flag.
For a baseline per file and rule, ESLint also has
bulk suppressions.
They apply to errors, not warnings. eslint --suppress-all records
existing violations; eslint --prune-suppressions removes resolved entries.
Keep new code strict
You can enforce a rule in new code while leaving legacy code at warn.
Add these objects after the main ESLint config object and before the
component-directory override:
{
files: ["app/**", "features/**"],
rules: { "shadcn/no-restyle": ["error", { allow: ["layout"] }] },
},
{
files: ["legacy/**"],
rules: { "shadcn/no-restyle": ["warn", { allow: ["layout"] }] },
},
To exempt a folder, turn off the specific rule there. Other lint checks still run:
{ files: ["marketing/**"], rules: { "shadcn/no-restyle": "off" } }
Fix findings
- Use an existing variant for a component's appearance.
- Use a contract when callers should control part of its styling.
- Use suggested tokens or scale values when they match the design.
- Review new tokens and variants before adding them.
For example, a title can allow typography through a contract:
"shadcn/no-restyle": ["warn", {
allow: ["layout"],
contracts: [
{ pattern: "^CardTitle$", allow: ["layout", "typography"] },
],
}]
<CardTitle className="text-sm">Account settings</CardTitle>
A contract overrides the keys it writes and inherits the rest, so a
contract that writes allow restates layout when the component
should keep it. See
Configuring your design system for help choosing variants and contracts.
Add more rules
When a rule is clean, change it to error. Add other rules at warn
first, then promote each one as you resolve its findings. A configuration
with all five core rules enabled looks like this:
rules: {
"shadcn/no-restyle": ["error", { allow: ["layout"] }],
"shadcn/no-raw-colors": "error",
"shadcn/no-arbitrary-values": ["error", { allow: ["layout"] }],
"shadcn/no-inline-styles": "error",
"shadcn/require-static-classes": "error",
}
Update the component-directory override too. Components own their
appearance and may need structural values such as ring-[3px]:
{
files: ["components/ui/**"],
rules: {
"shadcn/no-restyle": "off",
"shadcn/no-arbitrary-values": "off",
"shadcn/require-static-classes": "off",
},
}
Adjust the path to your component directory. no-raw-colors and
no-inline-styles stay enabled inside it.
Add no-unknown-classes separately, at
warn first. Classes supplied by other stylesheets may need an allow
entry. Remove --max-warnings once all enabled rules are errors.
Agents
Add your lint command to package.json, then put this in AGENTS.md:
After making changes, run `npm run lint` and fix all errors.
Review new tokens, variants, and exceptions in the resulting changes.
Exceptions
Document an intentional exception next to the code:
// eslint-disable-next-line shadcn/no-raw-colors -- Partner brand color, approved by design.
<span className="bg-amber-400">Sponsor</span>
rg "eslint-disable.*shadcn/" finds these comments. You can require a
reason with require-description from
@eslint-community/eslint-plugin-eslint-comments.