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.