Comparison

Deslint vs. stylelint: they do different jobs

Stylelint is the mature, de-facto linter for authored CSS. Deslint lints the design-system surface that AI agents like Cursor and Claude Code actually touch — JSX className drift, arbitrary Tailwind values, design-token violations. Most teams shipping modern frontend should run both.

Last updated April 17, 2026. Written by the deslint team; we’re trying to be honest, not to sell.

TL;DR at a glance

QuestionWinner
Authored .css / .scss (nesting, ordering, syntax)stylelint
Tailwind arbitrary values in JSX (bg-[#1a5276])Deslint
Raw hex colors in className / style propsDeslint
Design-token enforcement across a monorepoDeslint
CSS-in-JS (emotion, styled-components)Both
CI gate, SARIF, editor integrationBoth
Works with AI coding agents via MCPDeslint

What each tool is actually built for

stylelint

A CSS linter. It parses .css, .scss, .less, .vue, and style blocks, then runs rules against the CSS AST. It catches bad selectors, invalid values, disallowed nesting, ordering problems, and vendor prefixes you forgot to strip.

If you write CSS by hand — design-system source files, global styles, utility stylesheets — stylelint is the right tool. It is mature, well-maintained, and has an enormous plugin ecosystem.

Deslint

A JSX/TSX linter focused on the design-system surface. It parses your components and runs 34 deterministic rules against what AI coding agents actually write — className strings, style props, Tailwind utilities, inline hex colors.

Its job is to catch the stuff stylelint structurally can’t see: bg-[#1a5276] sitting in a React component, a one-off p-[17px], a text-blue-500 that should have been a token.

Six real questions, answered honestly

01

Who catches a raw hex in className="bg-[#1a5276]"?

Stylelint never sees this. It runs on CSS files, not JSX string literals, so a Tailwind arbitrary value inside a React className is invisible to it — even with postcss-lit or template parsers, the string isn’t CSS yet at lint time.

Deslint’s no-arbitrary-colors rule flags it at the JSX level, before Tailwind expands it. The full story is in the hidden cost of Tailwind arbitrary values.

Verdict: deslint.

02

Who enforces ordering inside an authored tokens.css?

Stylelint. This is its home turf. If you author CSS custom properties, keep a design-token file, or maintain a utility stylesheet, stylelint’s rule ecosystem — declaration-block-no-redundant-longhand-properties, order/properties-order, selector-max-specificity — is unmatched.

Deslint doesn’t parse CSS. It deliberately doesn’t compete here. If someone sells you “replace your stylelint,” they’re selling you something worse.

Verdict: stylelint.

03

Who catches a style={{ color: '#fa0a3e' }} inline prop?

Stylelint can, but only if you wire up a template-literal plugin and the value is in a tagged template or CSS-in-JS string. A plain object-literal style prop on a React element is outside its scope.

Deslint’s no-inline-styles and no-raw-hex were written specifically for this case — it’s the single most common drift pattern in AI-generated React code.

Verdict: deslint.

04

Who imports your Figma tokens and enforces them?

Neither does it end-to-end, but the gap is narrower for deslint. Deslint’s .deslintrc.json accepts a design-system config (palette, spacing scale, type scale) which the rules then enforce across JSX. Tokens Studio / Style Dictionary export to that shape in one step.

Stylelint can lint custom properties you’ve already authored, but it has no concept of “this component used a color that isn’t in the palette.” That’s a JSX-level question.

Verdict: deslint, for the cross-component enforcement. Stylelint for the token file itself.

05

Who integrates with AI coding agents (Claude Code, Cursor, Windsurf)?

Deslint ships an MCP server that plugs directly into Claude Code, Cursor, Windsurf, and Codex. The agent can run analyze_project, enforce_budget, and compliance_check before it finalizes a generation — the lint happens inside the authoring loop, not after.

Stylelint is a post-hoc linter with no MCP surface. You can wire it into a CI gate or editor plugin, but the agent doesn’t see it during generation.

Verdict: deslint.

06

Who works with CI, editor, and SARIF/GitHub code-scanning?

Both. Stylelint has first-class editor plugins, a stable CLI, and mature CI patterns. Deslint ships an ESLint plugin, a standalone CLI (deslint scan), a GitHub Action, and SARIF output for GitHub Advanced Security and Azure DevOps.

Neither one replaces the other at the CI layer. You can (and should) run them both in the same pipeline — they gate different surfaces.

Verdict: both — they coexist cleanly.

When to use which

Use stylelint alone if:

Your codebase is mostly authored CSS or SCSS, your components don’t embed color/spacing values in JSX, you don’t use Tailwind, and AI-generated code is a small fraction of what ships.

Use deslint alone if:

You’re Tailwind-only, your team barely touches CSS files directly, and most of your drift lives in className strings and inline styles written by AI agents.

Use both if:

You maintain a design-system source (tokens, primitives, global styles) and ship product components in JSX/TSX with AI assistance. This is the common case, and the two tools don’t overlap — they gate different parts of your pipeline.

Running them together

The cleanest setup we’ve seen: stylelint gates the packages/design-system/**/*.css and globals.css paths, deslint gates the apps/**/*.tsx product surface, and the MCP server runs during AI-assisted authoring. Three gates, zero overlap.

# CI pipeline
pnpm stylelint "packages/**/*.{css,scss}"
pnpm deslint scan "apps/**/*.{ts,tsx}" --format sarif --output deslint.sarif

# Local editor
# stylelint plugin + ESLint (deslint) plugin, both enabled

# AI authoring loop
# Claude Code / Cursor / Windsurf → deslint MCP tools

Ready to add deslint alongside stylelint?

It takes about two minutes. The getting-started guide walks through the ESLint plugin, the CLI, and the MCP server. None of them require a cloud account.