npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

eslint-plugin-tailwindcss-condense

v0.3.0

Published

Autofix equivalent Tailwind CSS utilities and related variant order in ESLint.

Readme

eslint-plugin-tailwindcss-condense

Autofix Tailwind CSS class strings by collapsing safe equivalent utilities and keeping related variants close without loading Tailwind internals.

Why use it

eslint-plugin-tailwindcss-condense is intentionally narrower than a global Tailwind class sorter. It focuses on safe autofixes that reduce class noise while preserving semantic meaning:

  • Collapse equivalent utility groups to shorter Tailwind shorthands.
  • Keep related base, responsive, and state variants close together.
  • Normalize variant chains without globally reordering unrelated utilities.
  • Read Tailwind v4 @theme tokens without depending on Tailwind internal APIs.
  • Touch only static class strings that ESLint can safely autofix.

What it fixes

tailwindcss-condense/normalize-class-spacing trims and normalizes class spacing:

- <div className="  pt-4   pb-4  " />
+ <div className="pt-4 pb-4" />

tailwindcss-condense/prefer-class-shorthand makes equivalent utilities shorter:

- <div className="pt-4 pb-4 border-l-2 border-r-2" />
+ <div className="py-4 border-x-2" />

tailwindcss-condense/group-related-classes keeps related semantic families grouped:

- <div className="bg-red-500 text-white hover:bg-red-600" />
+ <div className="bg-red-500 hover:bg-red-600 text-white" />

tailwindcss-condense/sort-class-variants orders variants only inside the same semantic family:

- <div className="lg:p-8 sm:p-2 md:p-5" />
+ <div className="sm:p-2 md:p-5 lg:p-8" />

Install

npm i -D eslint eslint-plugin-tailwindcss-condense tailwindcss

Requirements:

  • Node.js >=20.11
  • ESLint v9 or v10 (ESLint v10 itself requires Node.js ^20.19.0 || ^22.13.0 || >=24)
  • Tailwind CSS v4
  • ESM flat config

Quick Start

import { defineConfig } from "eslint/config";
import tailwindcssCondense from "eslint-plugin-tailwindcss-condense";

export default defineConfig([
  {
    files: ["**/*.{js,jsx}"],
    languageOptions: {
      ecmaVersion: "latest",
      parserOptions: {
        ecmaFeatures: {
          jsx: true,
        },
      },
      sourceType: "module",
    },
  },
  ...tailwindcssCondense.configs["flat/recommended"],
]);

Then run ESLint with autofix enabled:

npx eslint . --fix

For TypeScript, Vue, or other frameworks that need a custom parser, keep your existing parser setup and add ...tailwindcssCondense.configs["flat/recommended"] after it. This plugin does not bundle a TypeScript or template parser.

Presets

flat/recommended enables every current rule as a warning:

| Rule | Purpose | Autofix | | --- | --- | --- | | tailwindcss-condense/normalize-class-spacing | Trim and normalize class separators | Yes | | tailwindcss-condense/prefer-class-shorthand | Collapse equivalent utilities to shorthands | Yes | | tailwindcss-condense/group-related-classes | Keep same-family utilities close | Yes | | tailwindcss-condense/sort-class-variants | Normalize and order variants inside a semantic family | Yes |

Manual rule setup:

import tailwindcssCondense from "eslint-plugin-tailwindcss-condense";

export default [
  {
    plugins: {
      "tailwindcss-condense": tailwindcssCondense,
    },
    rules: {
      "tailwindcss-condense/normalize-class-spacing": "warn",
      "tailwindcss-condense/prefer-class-shorthand": "warn",
      "tailwindcss-condense/group-related-classes": "warn",
      "tailwindcss-condense/sort-class-variants": "warn",
    },
  },
];

Theme Tokens

The plugin understands Tailwind core values, arbitrary values, and custom @theme tokens. It does not parse custom @utility definitions.

By default it auto-discovers common CSS entry files:

  • app/globals.css
  • src/app/globals.css
  • src/index.css
  • src/main.css
  • src/styles.css
  • src/assets/main.css
  • styles/globals.css
  • app.css
  • index.css

Next.js App Router projects are covered by the default theme discovery paths, including app/globals.css and src/app/globals.css.

For custom structures, set theme files explicitly:

export default [
  {
    settings: {
      tailwindcssCondense: {
        themeFiles: ["packages/web/styles/theme.css"],
      },
    },
  },
];

Relative CSS imports from theme files are followed. Package imports, URLs, and @utility blocks are ignored.

Configuration Reference

All options live under settings.tailwindcssCondense in ESLint flat config:

| Setting | Type | Default | Description | | --- | --- | --- | --- | | cwd | string | process.cwd() | Base directory used to resolve theme files. | | themeFiles | string[] | null | Explicit CSS files to parse for @theme tokens. | | autoDiscoverThemeFiles | boolean | true | Enables the common CSS entry file lookup listed above. | | callees | string[] | Common class helpers | Function and tag names whose static string values should be fixed. |

Class Helper Functions

The rules also run inside static strings passed to known class helper functions and tagged templates.

Default settings.tailwindcssCondense.callees:

| Callee | Typical source | Support | | --- | --- | --- | | classnames, classNames | classnames | String args, arrays, conditional object keys | | clsx | clsx | String args, arrays, conditional object keys | | cn | shadcn/ui-style helper | String args, arrays, conditional object keys | | cx | common alias / CVA helper | String args, arrays, conditional object keys | | cva | class-variance-authority | Base classes, variants, compound variant class/className | | tv | tailwind-variants | Base classes, slots, variants, compound variant classes | | twMerge, twJoin | tailwind-merge | String args and arrays | | ctl, tw | template literal helpers | Static tagged templates |

Override the list when your project uses a custom helper:

export default [
  {
    settings: {
      tailwindcssCondense: {
        callees: ["cn", "buttonClasses"],
      },
    },
  },
];

Only static strings are fixed. Classes are not moved across separate function arguments, array elements, or conditional branches.

Frameworks

The core support is ESLint AST based:

| Syntax | Requirement | Supported targets | | --- | --- | --- | | JSX/TSX | Your existing ESLint parser setup | Static class and className values | | Vue | vue-eslint-parser | Static class attributes | | Helper calls | Configured callees | Static strings, arrays, object keys, and supported CVA/TV shapes | | Tagged templates | Configured tag names | Static template literals without expressions |

Svelte, Astro, and other template syntaxes are future candidates when their ESLint parsers expose stable static class attributes. Dynamic class construction is out of scope for the MVP.

Rules

tailwindcss-condense/prefer-class-shorthand

Collapses safe groups to equivalent shorthand utilities.

Examples:

  • pt-4 pb-4 -> py-4
  • p-4 pt-4 -> p-4
  • px-4 py-4 -> p-4
  • w-6 h-6 -> size-6
  • border-l-2 border-r-2 -> border-x-2
  • content-center custom-class justify-center -> place-content-center custom-class
  • gap-x-gutter gap-y-gutter -> gap-gutter when --spacing-gutter exists in @theme

Full docs: docs/rules/prefer-class-shorthand.md

tailwindcss-condense/normalize-class-spacing

Trims surrounding class whitespace and collapses repeated separators to one space.

Examples:

  • " pt-4 pb-4" -> "pt-4 pb-4"
  • "pt-4 pb-4 " -> "pt-4 pb-4"
  • "pt-4 pb-4" -> "pt-4 pb-4"

Full docs: docs/rules/normalize-class-spacing.md

tailwindcss-condense/group-related-classes

Moves known classes in the same semantic family closer together.

Example:

- bg-red-500 text-white hover:bg-red-600
+ bg-red-500 hover:bg-red-600 text-white

Full docs: docs/rules/group-related-classes.md

tailwindcss-condense/sort-class-variants

Normalizes variant chains and orders variant classes only inside the same semantic family.

Examples:

  • lg:p-8 sm:p-2 md:p-5 -> sm:p-2 md:p-5 lg:p-8
  • hover:sm:bg-red-500 -> sm:hover:bg-red-500

Full docs: docs/rules/sort-class-variants.md

Scope and Non-Goals

In scope:

  • Core Tailwind utility families with safe semantic equivalence
  • @theme tokens
  • Arbitrary values
  • ESLint flat config
  • Static class strings

Out of scope:

  • Custom @utility inference
  • Tailwind internal APIs
  • Broad redundancy/conflict cleanup outside safe shorthand-equivalent reductions
  • Dynamic classes
  • Full global class sorting
  • Tailwind v3 compatibility claims

Compatibility with Class Sorters

This plugin can be used alongside tools such as prettier-plugin-tailwindcss. Use Prettier for canonical Tailwind class ordering when that is desired, and use this ESLint plugin for safe shorthand reductions and local semantic grouping.

Because the rules only operate on static strings and avoid Tailwind internals, projects can disable individual rules when another formatter owns that part of the class string.

Contributing

Issues and pull requests are welcome when they stay inside the safe-fix scope. See CONTRIBUTING.md for local checks, test expectations, and release validation.

License

MIT