ESLint plugin for Tailwind CSS usage
See the code
eslint-plugin-tailwindcssv3 to v4I spent countless days working on this plugin, and it is available to everyone for free.
If you benefit from my work and if you want to help me keep the project alive, consider becoming a sponsor.
GitHub Sponsors | thanks.dev Sponsors
💼 Configurations enabled in.
⚠️ Configurations set to warn in.
✅ Set in the recommended configuration.
🔧 Automatically fixable by the --fix CLI option.
💡 Manually fixable by editor suggestions.
| Name | Description | 💼 | ⚠️ | 🔧 | 💡 |
|---|---|---|---|---|---|
| classnames-order | Enforces a consistent order for the Tailwind CSS classnames, based on the compiler. | ✅ | 🔧 | ||
| enforces-canonical-classname | Enforces the canonical spelling of a classname, as resolved by the Tailwind CSS compiler. | ✅ | 🔧 | ||
| enforces-negative-arbitrary-values | Warns about - prefixed classnames using arbitrary values. | ✅ | 🔧 | ||
| enforces-shorthand | Avoid using multiple Tailwind CSS classnames when not required. | ✅ | 🔧 | ||
| important-modifier-suffix | In v4 you should place the ! at the very end of the class name. | ✅ | 🔧 | ||
| no-arbitrary-value | Forbid using arbitrary values in classnames. | ||||
| no-contradicting-classname | Avoid contradicting Tailwind CSS classnames. | ✅ | 💡 | ||
| no-custom-classname | Detects classnames which do not belong to Tailwind CSS. | ✅ | 💡 | ||
| no-unnecessary-arbitrary-value | Avoid unjustified arbitrary classnames. | ✅ | 🔧 | 💡 |
npm i -D eslint-plugin-tailwindcss
pnpmIf you are still using Tailwind CSS v3 and/or older ESLint versions, you can use
eslint-plugin-tailwindcss@3.x.x
eslint.config fileHere is a very basic example:
// 1. Import the plugin and defineConfig helper
import eslintPluginTailwindcss from "eslint-plugin-tailwindcss";
import { defineConfig } from "eslint/config";
export default defineConfig([
// 2. Include the recommended config
eslintPluginTailwindcss.configs["flat/recommended"] ||
eslintPluginTailwindcss.configs.recommended,
// 3. Define your own settings
{
settings: {
// Define the tailwindcss settings with the MANDATORY `cssConfigPath`
tailwindcss: {
cssConfigPath: "./src/styles/tailwind.css",
},
},
// Optional: Customize the rules to your needs
rules: {
"tailwindcss/classnames-order": "warn",
"tailwindcss/no-arbitrary-value": "warn",
"tailwindcss/no-custom-classname": [
"warn",
{ whitelist: ["custom\\-*"] },
],
"tailwindcss/no-contradicting-classname": "warn",
},
},
]);
cssConfigPathcan be an absolute or a relative path. If you provide a relative path, the plugin will attempt to convert it into an absolute path.
The plugin also exports the type PluginSettings which you can use to benefit from autocomplete and validation directly inside your eslint.config file.
// @ts-check to force type checking/** @type {import('eslint-plugin-tailwindcss').PluginSettings} */Here is a snippet, notice the object is surrounded by parentheses ({...}):
settings: {
tailwindcss:
/** @type {import('eslint-plugin-tailwindcss').PluginSettings} */
({
cssConfigPath: './styles/tailwind.css',
}),
},
You can also:
Most of the rules solely use the shared settings (shared across all the plugin rules). Learn about eslint shared settings from the official documentation.
Here is a fully detailed example of shared settings:
// eslint.config.mjs
{
settings: {
tailwindcss: {
// Attributes/props that could contain Tailwind CSS classes...
// Optional, default values: ["class", "className", "ngClass", "@apply"]
attributes: ["class"],
// The (absolute or relative) path pointing to you main Tailwind CSS v4 config file.
// It must be a `.css` file (v4), not a `.js` file (v3)
// REQUIRED, as the default value may not work out-of-the-box
cssConfigPath: "./styles/tailwind.css",
// Functions/tagFunctions that will be parsed by the plugin.
// Optional, default values: ["classnames", "classNames", "clsx", "cn", "ctl", "cva", "tv", "tw", "twMerge", "twJoin"]
functions: ["twClasses"],
// Within the list of functions, which should we check the keys instead of the values (used for `clsx`, etc.)
// Optional, default values: ["classnames", "classNames", "clsx"]
parseKeyFunctions: ["clsx"],
// Keys to be ignored in object expressions
// Optional, default values: ["defaultVariants", "compoundVariants", "compoundSlots"]
ignoredKeys: ["defaultVariants", "compoundVariants", "compoundSlots", "specificKey"],
// Max size of the Set or Map objects used for caching
// Optional, default value: 250_000
cacheMaxSize: 150_000,
// Max lifetime of the cache set in ms
// Optional, default value: 10 * 60 * 1000 (10 minutes)
cacheMaxAge: 60 * 1000,
},
}
}
The default settings are exported via the DEFAULT_SETTINGS.
The project is open to all developers, you can contribute to eslint-plugin-tailwindcss.
However, make sure to discuss the issue or the feature you wish to implement prior to getting to work unless you feel adventurous.
Overall
Maintained
Code review
Latest release
Releases this year
(top 24 of 36)
1,989 followers · starred Aug 2022
401 followers · starred Nov 2025
670 followers · starred Mar 2026
1,749 followers · starred Jan 2022
ESLint plugin for Tailwind CSS usage
See the code
eslint-plugin-tailwindcssv3 to v4I spent countless days working on this plugin, and it is available to everyone for free.
If you benefit from my work and if you want to help me keep the project alive, consider becoming a sponsor.
GitHub Sponsors | thanks.dev Sponsors
💼 Configurations enabled in.
⚠️ Configurations set to warn in.
✅ Set in the recommended configuration.
🔧 Automatically fixable by the --fix CLI option.
💡 Manually fixable by editor suggestions.
| Name | Description | 💼 | ⚠️ | 🔧 | 💡 |
|---|---|---|---|---|---|
| classnames-order | Enforces a consistent order for the Tailwind CSS classnames, based on the compiler. | ✅ | 🔧 | ||
| enforces-canonical-classname | Enforces the canonical spelling of a classname, as resolved by the Tailwind CSS compiler. | ✅ | 🔧 | ||
| enforces-negative-arbitrary-values | Warns about - prefixed classnames using arbitrary values. | ✅ | 🔧 | ||
| enforces-shorthand | Avoid using multiple Tailwind CSS classnames when not required. | ✅ | 🔧 | ||
| important-modifier-suffix | In v4 you should place the ! at the very end of the class name. | ✅ | 🔧 | ||
| no-arbitrary-value | Forbid using arbitrary values in classnames. | ||||
| no-contradicting-classname | Avoid contradicting Tailwind CSS classnames. | ✅ | 💡 | ||
| no-custom-classname | Detects classnames which do not belong to Tailwind CSS. | ✅ | 💡 | ||
| no-unnecessary-arbitrary-value | Avoid unjustified arbitrary classnames. | ✅ | 🔧 | 💡 |
npm i -D eslint-plugin-tailwindcss
pnpmIf you are still using Tailwind CSS v3 and/or older ESLint versions, you can use
eslint-plugin-tailwindcss@3.x.x
eslint.config fileHere is a very basic example:
// 1. Import the plugin and defineConfig helper
import eslintPluginTailwindcss from "eslint-plugin-tailwindcss";
import { defineConfig } from "eslint/config";
export default defineConfig([
// 2. Include the recommended config
eslintPluginTailwindcss.configs["flat/recommended"] ||
eslintPluginTailwindcss.configs.recommended,
// 3. Define your own settings
{
settings: {
// Define the tailwindcss settings with the MANDATORY `cssConfigPath`
tailwindcss: {
cssConfigPath: "./src/styles/tailwind.css",
},
},
// Optional: Customize the rules to your needs
rules: {
"tailwindcss/classnames-order": "warn",
"tailwindcss/no-arbitrary-value": "warn",
"tailwindcss/no-custom-classname": [
"warn",
{ whitelist: ["custom\\-*"] },
],
"tailwindcss/no-contradicting-classname": "warn",
},
},
]);
cssConfigPathcan be an absolute or a relative path. If you provide a relative path, the plugin will attempt to convert it into an absolute path.
The plugin also exports the type PluginSettings which you can use to benefit from autocomplete and validation directly inside your eslint.config file.
// @ts-check to force type checking/** @type {import('eslint-plugin-tailwindcss').PluginSettings} */Here is a snippet, notice the object is surrounded by parentheses ({...}):
settings: {
tailwindcss:
/** @type {import('eslint-plugin-tailwindcss').PluginSettings} */
({
cssConfigPath: './styles/tailwind.css',
}),
},
You can also:
Most of the rules solely use the shared settings (shared across all the plugin rules). Learn about eslint shared settings from the official documentation.
Here is a fully detailed example of shared settings:
// eslint.config.mjs
{
settings: {
tailwindcss: {
// Attributes/props that could contain Tailwind CSS classes...
// Optional, default values: ["class", "className", "ngClass", "@apply"]
attributes: ["class"],
// The (absolute or relative) path pointing to you main Tailwind CSS v4 config file.
// It must be a `.css` file (v4), not a `.js` file (v3)
// REQUIRED, as the default value may not work out-of-the-box
cssConfigPath: "./styles/tailwind.css",
// Functions/tagFunctions that will be parsed by the plugin.
// Optional, default values: ["classnames", "classNames", "clsx", "cn", "ctl", "cva", "tv", "tw", "twMerge", "twJoin"]
functions: ["twClasses"],
// Within the list of functions, which should we check the keys instead of the values (used for `clsx`, etc.)
// Optional, default values: ["classnames", "classNames", "clsx"]
parseKeyFunctions: ["clsx"],
// Keys to be ignored in object expressions
// Optional, default values: ["defaultVariants", "compoundVariants", "compoundSlots"]
ignoredKeys: ["defaultVariants", "compoundVariants", "compoundSlots", "specificKey"],
// Max size of the Set or Map objects used for caching
// Optional, default value: 250_000
cacheMaxSize: 150_000,
// Max lifetime of the cache set in ms
// Optional, default value: 10 * 60 * 1000 (10 minutes)
cacheMaxAge: 60 * 1000,
},
}
}
The default settings are exported via the DEFAULT_SETTINGS.
The project is open to all developers, you can contribute to eslint-plugin-tailwindcss.
However, make sure to discuss the issue or the feature you wish to implement prior to getting to work unless you feel adventurous.
Overall
Maintained
Code review
Latest release
Releases this year
(top 24 of 36)
1,989 followers · starred Aug 2022
401 followers · starred Nov 2025
670 followers · starred Mar 2026
1,749 followers · starred Jan 2022