DEV Community

Cover image for Why Your Tailwind Project Leaks Spacing (And How to Fix It in 5 Minutes)
Petri Lahdelma
Petri Lahdelma

Posted on

Why Your Tailwind Project Leaks Spacing (And How to Fix It in 5 Minutes)

Every Tailwind project starts clean. p-4, gap-2, m-8 — the spacing scale holds.

Then someone writes p-[13px].

Then another dev adds gap-[7px] because "it just looks better." Then a third person commits margin: 15px in a CSS Module because they didn't know about the scale.

Six months later, git grep finds 47 unique spacing values across 200 files. Your 8pt grid is a suggestion, not a rule.

This is spacing drift. It happens in every project that relies on convention instead of enforcement.

The problem with Tailwind's arbitrary values

Tailwind v4 made CSS-first configuration the default. That's great for tokens:

@theme {
  --spacing-1: 4px;
  --spacing-2: 8px;
  --spacing-3: 12px;
  --spacing-4: 16px;
}
Enter fullscreen mode Exit fullscreen mode

But nothing stops a developer from writing p-[13px] in a component. Prettier won't catch it. ESLint won't catch it. TypeScript won't catch it.

Tailwind gives you a scale. It doesn't enforce it.

What Rhythmguard does

Rhythmguard is a Stylelint plugin that enforces your spacing scale and design tokens in both CSS declarations and Tailwind class strings.

Three rules, one purpose:

Rule What it catches
use-scale padding: 13px → "Use 12px or 16px"
prefer-token gap: 16px → "Use var(--spacing-4)"
no-offscale-transform translateY(18px) → "Use 16px or 24px"

All three autofix. 13px becomes 12px. 16px becomes var(--spacing-4). No manual cleanup.

Setup: 5 minutes for a Next.js + Tailwind project

npm install --save-dev stylelint stylelint-plugin-rhythmguard
Enter fullscreen mode Exit fullscreen mode

.stylelintrc.json:

{
  "extends": ["stylelint-plugin-rhythmguard/configs/react-tailwind"]
}
Enter fullscreen mode Exit fullscreen mode

That's it for CSS files. For Tailwind class strings in JSX/TSX, add the ESLint companion:

eslint.config.js:

import rhythmguard from 'stylelint-plugin-rhythmguard/eslint';

export default [
  {
    plugins: { 'rhythmguard-tailwind': rhythmguard },
    rules: {
      'rhythmguard-tailwind/tailwind-class-use-scale': [
        'error',
        { scale: [0, 4, 8, 12, 16, 24, 32] }
      ],
    },
  },
];
Enter fullscreen mode Exit fullscreen mode

Now p-[13px] in your JSX gets caught and autofixed to p-[12px].

Tailwind v4: Zero-config token governance

If your project uses Tailwind v4 with @theme blocks:

@theme {
  --spacing-4: 16px;
  --spacing-3: 12px;
}
Enter fullscreen mode Exit fullscreen mode

Rhythmguard automatically extracts these as token mappings. When you write padding: 16px, it autofixes to padding: var(--spacing-4). No tokenMap config needed.

Before/after: a real CSS Module

Before:

.card {
  padding: 13px;
  margin-bottom: 7px;
  gap: 15px;
  border-radius: 5px;
}
Enter fullscreen mode Exit fullscreen mode

After autofix:

.card {
  padding: 12px;
  margin-bottom: 8px;
  gap: 16px;
  border-radius: 4px;
}
Enter fullscreen mode Exit fullscreen mode

After token migration:

.card {
  padding: var(--spacing-3);
  margin-bottom: var(--spacing-2);
  gap: var(--spacing-4);
  border-radius: var(--radius-1);
}
Enter fullscreen mode Exit fullscreen mode

Audit before you enforce

Not ready to enforce yet? Run an audit first:

npx rhythmguard audit ./src
Enter fullscreen mode Exit fullscreen mode
Rhythmguard Audit: ./src

Files scanned:     47
Files with issues: 12 (25%)

Off-scale values: 34
  13px       ×8
  7px        ×6
  15px       ×5

Token opportunities: 18
  16px → var(--spacing-4)  ×9
  8px  → var(--spacing-2)  ×5
Enter fullscreen mode Exit fullscreen mode

Paste this in a PR description. Your team lead will understand the problem immediately.

Works with your tools

Rhythmguard supports the token workflows modern teams actually use:

  • Tailwind v4 @theme — auto-extracted, zero config
  • Tailwind v3 config — reads theme.spacing from JS config
  • W3C DTCG tokens — Style Dictionary, Tokens Studio, Figma Variables export
  • CSS custom propertiesvar(--space-*) from any source
  • cn/clsx/cva/twMerge — ESLint rule catches arbitrary values in all utility helpers

Framework configs for React/Next.js, Vue, Lit, Astro, SvelteKit.

Why not just use Prettier / eslint-plugin-tailwindcss?

Prettier orders your classes. It doesn't know if p-[13px] is on your scale.

eslint-plugin-tailwindcss checks class name conventions. It doesn't enforce which values are allowed in arbitrary brackets.

Rhythmguard is the only tool that governs the actual spacing values — in CSS declarations AND in Tailwind class strings.

Get started

npm install --save-dev stylelint stylelint-plugin-rhythmguard
npx rhythmguard init
npx rhythmguard audit ./src
Enter fullscreen mode Exit fullscreen mode

Three commands. Five minutes. Your spacing scale becomes a rule, not a suggestion.

GitHub: stylelint-plugin-rhythmguard
npm: stylelint-plugin-rhythmguard

Top comments (0)