sailop
blogscanpricing
← Back to blog
March 16, 20268 min read

Sailop vs ESLint: Why Design Needs Its Own Linter

ESLint catches code quality issues. Sailop catches design quality issues. They are complementary tools solving different problems. Here is why you need both.

Every modern frontend project runs ESLint. It catches unused variables, enforces consistent formatting, and prevents common JavaScript mistakes. But ESLint has a blind spot the size of an ocean: it has zero opinions about what your code looks like when it renders in a browser. That is the gap Sailop fills.

What ESLint Catches

ESLint operates on the abstract syntax tree of your JavaScript or TypeScript code. It understands variables, functions, imports, and control flow. Here is what it is good at:

// ESLint catches this:
const x = 5;  // unused variable
if (x = 5) {} // assignment instead of comparison
import { useState } from 'react'
useState()     // hooks called outside component

// ESLint enforces this:
const name = 'hello';  // prefer const over let
function calc(a: number): number { return a * 2; }  // consistent return types

ESLint rules are about code correctness and consistency. They ask: "Is this code well-structured? Does it follow the team's conventions? Will it cause bugs?"

What ESLint Cannot Catch

ESLint has no concept of visual output. It parses code syntax, not rendered pixels. These patterns are invisible to ESLint:

// ESLint sees valid code. Sailop sees AI slop.
<div className="bg-blue-500 rounded-lg shadow-md p-6
  transition-all duration-300 ease-in-out">
  <h3 className="text-xl font-bold text-white">Feature</h3>
  <p className="text-blue-100 mt-2">Description here.</p>
</div>

This code passes every ESLint rule. The JSX is valid. The className strings are properly formatted. The component structure is correct. But visually, it is the most generic pattern on the web: blue card, rounded corners, shadow, transition-all, ease-in-out. It is AI slop, and ESLint cannot see it.

What Sailop Catches

Sailop parses the same files but looks at different things. Instead of checking syntax trees, it checks visual declarations: colors, fonts, spacing, animations, layout patterns, and component structures.

sailop check ./src/components/FeatureCard.tsx

# Findings:
# [HIGH]   color-blue-range: Primary color hue 217 is in AI-default band (200-290)
# [HIGH]   animation-transition-all: transition-all detected, specify exact properties
# [HIGH]   animation-ease-in-out: ease-in-out is an AI default easing
# [MEDIUM] component-rounded-uniform: rounded-lg used on all elements
# [MEDIUM] component-shadow-md: shadow-md is the #1 AI shadow pattern
# [LOW]    spacing-4px-grid: All spacing values are multiples of 4px
#
# Score: 76/100 (Grade D)

Sailop found six issues in the same file that ESLint found zero issues in. That is not because ESLint is bad. It is because they check completely different dimensions of code quality. To understand all seven dimensions Sailop measures, read what is AI slop.

The Comparison Table

| Dimension | ESLint | Sailop | |-----------|--------|--------| | Unused variables | Yes | No | | Type safety | Yes (with TS) | No | | Import order | Yes | No | | Color choices | No | Yes (12 rules) | | Typography patterns | No | Yes (11 rules) | | Layout defaults | No | Yes (10 rules) | | Animation quality | No | Yes (10 rules) | | Component uniformity | No | Yes (10 rules) | | Spacing patterns | No | Yes (10 rules) | | HTML structure | Partial | Yes (10 rules) | | Accessibility | Plugin | Partial |

ESLint covers code quality. Sailop covers design quality. The overlap is nearly zero. They are complementary, not competitive.

Why Existing ESLint Plugins Do Not Solve This

You might think: "Can't I write ESLint rules for CSS classes?" Technically, yes. There are ESLint plugins that lint Tailwind classes. But they solve a different problem.

// eslint-plugin-tailwindcss catches:
<div className="bg-blue-500 text-white p-6 bg-red-500">
// ^ duplicate background class

// It does NOT catch:
<div className="bg-blue-500 rounded-lg shadow-md p-6
  transition-all duration-300 ease-in-out">
// ^ perfectly valid Tailwind, but maximum AI slop

Tailwind ESLint plugins validate that classes exist and are not duplicated. They enforce Tailwind's syntax rules. They have no concept of what the combination of those classes looks like visually or whether that combination matches AI-default patterns.

Sailop's analysis is semantic. It does not just check individual classes. It checks combinations. A single rounded-lg is not a problem. But rounded-lg + shadow-md + bg-blue-500 + transition-all on the same element is a high-confidence AI pattern match. Our definitive list of 90+ AI design patterns catalogs every combination Sailop detects.

Running Them Together

The ideal setup runs both tools in your CI pipeline:

# In your CI/CD script:

# Step 1: Code quality
npx eslint ./src --max-warnings 0

# Step 2: Type safety
npx tsc --noEmit

# Step 3: Tests
npx vitest run

# Step 4: Design quality
npx sailop check ./src --max-score 50

Each step catches a different class of problems:

  • ESLint catches code patterns
  • TypeScript catches type errors
  • Tests catch behavioral bugs
  • Sailop catches visual homogeneity

If any step fails, the build fails. You get full-stack quality enforcement. For a detailed walkthrough of pipeline setup, see CI/CD for design: catching AI slop before it ships.

The Pre-Commit Hook Setup

For faster feedback, run both as pre-commit hooks:

# Install husky for git hooks
npm install -D husky
npx husky init

# .husky/pre-commit
npx lint-staged
// package.json
{
  "lint-staged": {
    "*.{ts,tsx}": [
      "eslint --fix",
      "sailop check --max-score 60"
    ],
    "*.css": [
      "sailop check --max-score 60"
    ]
  }
}

ESLint runs first with auto-fix enabled. Then Sailop checks the result. If the visual patterns score too high on the AI similarity scale, the commit is blocked.

Different Configurations for Different Teams

ESLint has shareable configs (airbnb, standard, google). Sailop has similar presets:

# Strict: all 73 rules, max score 30
sailop check ./src --preset strict

# Moderate: 50 most impactful rules, max score 50
sailop check ./src --preset moderate

# Minimal: only high-severity rules, max score 70
sailop check ./src --preset minimal

Start with minimal and tighten over time, the same way you would adopt ESLint rules gradually.

What Happens When Both Disagree

Sometimes ESLint and Sailop pull in different directions. ESLint's import-order rule might group CSS imports differently from what Sailop expects. In practice, this is rare because they operate on different dimensions. But when it happens, the fix is usually a Sailop comment override:

{/* sailop-disable component-rounded-uniform */}
<div className="rounded-lg shadow-md p-6">
  {/* This component intentionally uses uniform rounding */}
</div>
{/* sailop-enable component-rounded-uniform */}

This is the same pattern as // eslint-disable-next-line. You acknowledge the finding and override it with justification.

The Quality Stack

In 2026, a complete frontend quality stack looks like this:

TypeScript  → catches type errors
ESLint      → catches code quality issues
Prettier    → enforces formatting
Vitest      → catches behavioral bugs
Sailop      → catches design quality issues

Each tool is best in class at its specific job. None of them overlap significantly. Together, they catch the full spectrum of issues that can make it into production.

npm install -g sailop
sailop check ./src --max-score 50

Add Sailop to your quality stack. ESLint keeps your code clean. Sailop keeps your design unique. Read our complete guide to anti-AI design for the full workflow. Get started at sailop.com.

Try Sailop

Scan your frontend for AI patterns. Generate a unique design system. Ship code that looks intentional.

Free scannpm i -g sailop
Share this article
Share on X
Previous
How to Build a Unique Landing Page in 2026 (Without Looking AI-Generated)
Next
The Terminal Mockup Problem: Why Those 3 Dots Ruin Your Design
On this page
What ESLint CatchesWhat ESLint Cannot CatchWhat Sailop CatchesThe Comparison TableWhy Existing ESLint Plugins Do Not Solve ThisRunning Them TogetherThe Pre-Commit Hook SetupDifferent Configurations for Different TeamsWhat Happens When Both DisagreeThe Quality Stack
Sailop 2026All articles