Socket
Socket
Sign inDemoInstall

eslint-plugin-tailwindcss

Package Overview
Dependencies
Maintainers
0
Versions
183
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint-plugin-tailwindcss - npm Package Compare versions

Comparing version 3.17.3 to 4.0.0-alpha.0

docs/rules/my-rule.md

37

lib/index.js

@@ -1,28 +0,11 @@

/**
* @fileoverview Rules enforcing best practices while using Tailwind CSS
* @author François Massart
*/
'use strict';
//------------------------------------------------------------------------------
// Plugin Definition
//------------------------------------------------------------------------------
// import all rules in lib/rules
var base = __dirname + '/rules/';
module.exports = {
rules: {
'classnames-order': require(base + 'classnames-order'),
'enforces-negative-arbitrary-values': require(base + 'enforces-negative-arbitrary-values'),
'enforces-shorthand': require(base + 'enforces-shorthand'),
'migration-from-tailwind-2': require(base + 'migration-from-tailwind-2'),
'no-arbitrary-value': require(base + 'no-arbitrary-value'),
'no-contradicting-classname': require(base + 'no-contradicting-classname'),
'no-custom-classname': require(base + 'no-custom-classname'),
'no-unnecessary-arbitrary-value': require(base + 'no-unnecessary-arbitrary-value'),
},
configs: {
recommended: require('./config/recommended'),
'flat/recommended': require('./config/flat-recommended'),
},
"use strict";
const package_json_1 = require("../package.json");
const rules_1 = require("./rules");
const plugin = {
meta: {
name: package_json_1.name,
version: package_json_1.version,
},
rules: rules_1.rules,
};
module.exports = plugin;
{
"name": "eslint-plugin-tailwindcss",
"version": "3.17.3",
"version": "4.0.0-alpha.0",
"description": "Rules enforcing best practices while using Tailwind CSS",
"main": "lib/index.js",
"files": [
"docs/",
"lib/"
],
"type": "commonjs",
"exports": {
".": {
"default": "./lib/index.js"
},
"./package.json": "./package.json"
},
"keywords": [

@@ -10,48 +22,47 @@ "eslint",

"tailwind",
"tailwindcss"
"tailwindcss",
"turbo",
"typescript"
],
"author": "François Massart",
"homepage": "https://github.com/francoismassart/eslint-plugin-tailwindcss",
"repository": {
"type": "git",
"url": "https://github.com/francoismassart/eslint-plugin-tailwindcss"
"url": "https://github.com/francoismassart/eslint-plugin-tailwindcss",
"directory": "packages/eslint-plugin-tailwindcss"
},
"homepage": "https://github.com/francoismassart/eslint-plugin-tailwindcss",
"bugs": "https://github.com/francoismassart/eslint-plugin-tailwindcss/issues",
"main": "lib/index.js",
"author": "François Massart",
"license": "MIT",
"scripts": {
"test": "npm run test:base && npm run test:integration",
"test:base": "mocha \"tests/lib/**/*.js\"",
"test:integration": "mocha \"tests/integrations/*.js\" --timeout 60000"
"build": "tsc --build",
"build:time": "tsc --build --diagnostics",
"tsup": "tsup ./src/index.ts --outDir lib/",
"docs:init": "eslint-doc-generator --init-rule-docs",
"docs:update": "eslint-doc-generator",
"test:jest": "jest",
"test": "vitest"
},
"files": [
"lib"
],
"peerDependencies": {
"tailwindcss": "^3.4.0"
"tailwindcss": "next"
},
"dependencies": {
"fast-glob": "^3.2.5",
"postcss": "^8.4.4"
"@typescript-eslint/types": "^7.13.0",
"@typescript-eslint/utils": "^7.13.0",
"eslint": "^8.56.0"
},
"devDependencies": {
"@angular-eslint/template-parser": "^15.2.0",
"@tailwindcss/aspect-ratio": "^0.4.2",
"@tailwindcss/forms": "^0.5.3",
"@tailwindcss/line-clamp": "^0.4.2",
"@tailwindcss/typography": "^0.5.8",
"@typescript-eslint/parser": "^5.50.0",
"autoprefixer": "^10.4.0",
"daisyui": "^2.6.4",
"eslint": "^8.57.0",
"mocha": "^10.2.0",
"semver": "^7.6.0",
"tailwindcss": "^3.4.0",
"typescript": "4.3.5",
"vue-eslint-parser": "^9.4.2"
"@types/eslint": "^8.56.10",
"@types/jest": "^29.5.12",
"@typescript-eslint/parser": "^7.13.0",
"@typescript-eslint/rule-tester": "^7.13.0",
"eslint-doc-generator": "^1.7.1",
"jest": "^29.7.0",
"ts-jest": "^29.1.4",
"tsup": "^8.1.0",
"typescript": "^5.4.5",
"vitest": "^1.6.0"
},
"packageManager": "npm@10.2.5+sha256.8002e3e7305d2abd4016e1368af48d49b066c269079eeb10a56e7d6598acfdaa",
"engines": {
"node": ">=18.12.0"
},
"license": "MIT"
}
"node": ">=20.10.0"
}
}

@@ -1,300 +0,35 @@

# eslint-plugin-tailwindcss
# eslint-plugin-tailwindcss `v4` 🚧
![npm latest version](https://img.shields.io/npm/v/eslint-plugin-tailwindcss?style=for-the-badge) ![license](https://img.shields.io/npm/l/eslint-plugin-tailwindcss?style=for-the-badge) ![downloads](https://img.shields.io/npm/dt/eslint-plugin-tailwindcss?style=for-the-badge)
## Dev notes
![eslint-plugin-tailwindcss logo](.github/logo.png)
recommended package manager: `pnpm`
Rules enforcing best practices and consistency using [Tailwind CSS](https://tailwindcss.com/).
### Install
While you can use the official plugin [`prettier-plugin-tailwindcss`](https://www.npmjs.com/package/prettier-plugin-tailwindcss) for ordering your classnames...
`pnpm i`
**`eslint-plugin-tailwindcss` offers more than 5 other rules, that you can benefit from on top of `prettier-plugin-tailwindcss`. Sounds good ? Keep reading πŸ‘‡**
### Build
## Supported Rules
`pnpm build`
Learn more about each supported rules by reading their documentation:
### Test
- [`classnames-order`](docs/rules/classnames-order.md): order classnames for consistency and it makes merge conflict a bit easier to resolve
- [`enforces-negative-arbitrary-values`](docs/rules/enforces-negative-arbitrary-values.md): make sure to use negative arbitrary values classname without the negative classname e.g. `-top-[5px]` should become `top-[-5px]`
- [`enforces-shorthand`](docs/rules/enforces-shorthand.md): merge multiple classnames into shorthand if possible e.g. `mx-5 my-5` should become `m-5`
- [`migration-from-tailwind-2`](docs/rules/migration-from-tailwind-2.md) for easy upgrade from Tailwind CSS `v2` to `v3`.
Warning: at the moment you should [temporary turn off the `no-custom-classname`](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/88) rule if you want to see the warning from `migration-from-tailwind-2`
- [`no-arbitrary-value`](docs/rules/no-arbitrary-value.md): forbid using arbitrary values in classnames (turned off by default)
- [`no-custom-classname`](docs/rules/no-custom-classname.md): only allow classnames from Tailwind CSS and the values from the `whitelist` option
- [`no-contradicting-classname`](docs/rules/no-contradicting-classname.md): e.g. avoid `p-2 p-3`, different Tailwind CSS classnames (`pt-2` & `pt-3`) but targeting the same property several times for the same variant.
- [`no-unnecessary-arbitrary-value`](docs/rules/no-unnecessary-arbitrary-value.md): e.g. replacing `m-[1.25rem]` by its configuration based classname `m-5`
`pnpm test`
Using ESLint extension for Visual Studio Code, you will get these messages
![detected-errors](.github/output.png)
### Docs
You can can the same information on your favorite command line software as well.
`pnpm docs:init` will create new files for each rule if necessary.
## 🀝 Support `eslint-plugin-tailwindcss`
`pnpm docs:update` will update existing files and the rules list.
| πŸ₯° How you can support us? | πŸ’ͺ They did it! |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Premium Sponsors** <br /> Support us by becoming a sponsor. <br /> [Become a recurring sponsor](https://github.com/sponsors/francoismassart?frequency=recurring) | <a href="https://daily.dev/" target="_blank"><img width="150" src="https://raw.githubusercontent.com/francoismassart/eslint-plugin-tailwindcss/master/sponsors/daily.dev.jpg"></a> |
| **Current Sponsors** <br /> Any amount is appreciated. | <a href="https://github.com/jonz94" target="_blank"><img src="https://avatars.githubusercontent.com/u/16042676?s=150&amp;v=4" width="75" height="75" style="border-radius:100%;" alt="@jonz94"></a> <a href="https://github.com/theMosaad" target="_blank"><img src="https://avatars.githubusercontent.com/u/48773133?s=150&amp;v=4" width="75" height="75" style="border-radius:100%;" alt="@theMosaad"></a> <a href="https://github.com/acewf" target="_blank"><img src="https://avatars.githubusercontent.com/u/4835572?s=150&amp;v=4" width="75" height="75" style="border-radius:100%;" alt="@acewf"></a> <a href="https://github.com/charkour" target="_blank"><img src="https://avatars.githubusercontent.com/u/33156025?s=150&amp;v=4" width="75" height="75" style="border-radius:100%;" alt="@charkour"></a> <a href="https://github.com/dailydotdev" target="_blank"><img class="avatar" src="https://avatars.githubusercontent.com/u/41463883?s=150&amp;v=4" width="75" height="75" style="border-radius:100%;" alt="@dailydotdev"></a> <a href="https://github.com/codecov" target="_blank"><img class="avatar" src="https://avatars.githubusercontent.com/u/8226205?s=150&amp;v=4" width="75" height="75" style="border-radius:100%;" alt="@codecov"></a> <a href="https://github.com/sourcegraph" target="_blank"><img class="avatar" src="https://avatars.githubusercontent.com/u/3979584?s=150&amp;v=4" width="75" height="75" style="border-radius:100%;" alt="@sourcegraph"></a> |
| **Past sponsors** <br /> Even if this is just a one-time thing. <br /> [Become a backer](https://github.com/sponsors/francoismassart?frequency=one-time) | <a href="https://github.com/aniravi24" target="_blank"><img src="https://avatars.githubusercontent.com/u/5902976?s=100&amp;v=4" width="50" height="50" style="border-radius:100%;" alt="@aniravi24"></a> <a href="https://github.com/mongolyy" target="_blank"><img src="https://avatars.githubusercontent.com/u/10972787?s=100&amp;v=4" width="50" height="50" style="border-radius:100%;" alt="@mongolyy"></a> <a href="https://github.com/t3dotgg" target="_blank"><img src="https://avatars.githubusercontent.com/u/6751787?s=100&amp;v=4" width="50" height="50" style="border-radius:100%;" alt="@t3dotgg"></a> |
| **Contributors** <br /> This project can evolve thanks to all the people who contribute. <br /> You are welcome to [contribute](CONTRIBUTING.md) to this project by reporting issues, feature requests or even opening Pull Requests. | <a href="https://github.com/francoismassart/eslint-plugin-tailwindcss/graphs/contributors"><img src="https://contrib.rocks/image?repo=francoismassart/eslint-plugin-tailwindcss&width=300&columns=4" /></a> |
| **Supporters** <br /> Talk about the plugin on your social networks | <a href="https://twitter.com/search?q=eslint-plugin-tailwindcss&src=recent_search_click" target="_blank">eslint-plugin-tailwindcss on Twitter</a> |
## Rules
## Latest changelog
<!-- begin auto-generated rules list -->
- fix: [`no-arbitrary-value` rule is too broad](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/318)
- fix: [support `tag.div` and `tag(Component)`](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/302) (by [nihalgonsalves](https://github.com/nihalgonsalves) πŸ™)
- feat: [**support flat config and ESLint 9**](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/330) (by [kazupon](https://github.com/kazupon) πŸ™)
- feat: new rule [**`no-unnecessary-arbitrary-value`**](docs/rules/no-unnecessary-arbitrary-value.md) πŸŽ‰
- fix: retro compatibility for older Tailwind CSS (before typescript config)
- fix: [composable touch action classnames](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/293)
- fix: [`shadow-md` + `shadow-[#color]`can be used together 🀝](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/298)
- fix: [`tabular-nums` and `slashed-zero` can be used together 🀝](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/316)
- fix: [`size-*` based `size`, `spacing`, `width` and `height` πŸ€“](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/315)
- fix: [there is no `size-screen` πŸ˜…](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/307)
- fix: [edge cases with whitespace in `enforces-shorthand`](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/308)(by [kachkaev](https://github.com/kachkaev) πŸ™)
- fix: [parsing spreads in function call returns](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/285)(by [egorpavlikhin](https://github.com/egorpavlikhin) πŸ™)
- feat: [support for Tailwind CSS 3.4.0](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/297)
- ci: [add github actions workflow](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/303) (by [nihalgonsalves](https://github.com/nihalgonsalves) πŸ™)
- fix: [bg-center mark as conflicting with bg-[image:xxx]](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/260)
- feat: [support enforcing truncate shorthand](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/255) (by [bezbac](https://github.com/bezbac) πŸ™)
- fix: [parsing spreads in object expressions](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/251) (by [bezbac](https://github.com/bezbac) πŸ™)
- fix: [do not handle non-ASCII whitespace as separator](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/246) (by [uhyo](https://github.com/uhyo) πŸ™)
- fix: [prefix support for named group/peer syntax](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/244) (by [bezbac](https://github.com/bezbac) πŸ™)
- feat: [support tailwind config in typescript](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/242) (by [quesabe](https://github.com/quesabe) πŸ™)
**You may have to upgrade your Tailwind CSS version to `3.3.2`**
πŸ’‘ Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
[View all releases on github](https://github.com/francoismassart/eslint-plugin-tailwindcss/releases)
| Name | Description | πŸ’‘ |
| :------------------------------- | :--------------------- | :-- |
| [my-rule](docs/rules/my-rule.md) | An example ESLint rule | πŸ’‘ |
## Screencasts on our YouTube Channel
| <a href="https://www.youtube.com/@eslint-plugin-tailwind-css"><img src=".github/youtube-eslint-plugin-tailwindcss-round.png" width="80" height="80" alt="YouTube Channel" /></a> | <span style="font-size:18px">[ESLint plugin Tailwind CSS](https://www.youtube.com/@eslint-plugin-tailwind-css)</span><br>youtube.com/@eslint-plugin-tailwindcss |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
## Installation
### 1. Install `eslint` and `eslint-plugin-tailwindcss`
You'll first need to install [ESLint](http://eslint.org):
```
$ npm i -D eslint eslint-plugin-tailwindcss
```
### 2. Create Configuration file
#### `.eslintrc`
Use .eslintrc.\* file to configure rules in ESLint < v9. See also: https://eslint.org/docs/latest/use/configure/.
```js
module.exports = {
root: true,
extends: ["plugin:tailwindcss/recommended"],
};
```
If you would like to know about configuration, Learn more in [ESLint docs](https://eslint.org/docs/latest/use/configure/configuration-files)
#### `eslint.config.js`
Use `eslint.config.js` file to configure rules. This is the default in ESLint v9, but can be used starting from ESLint v8.57.0. See also: https://eslint.org/docs/latest/use/configure/configuration-files-new.
```js
import tailwind from "eslint-plugin-tailwindcss";
export default [...tailwind.configs["flat/recommended"]];
```
If you would like to know about configuration, Learn more in [ESLint docs](https://eslint.org/docs/latest/use/configure/configuration-files-new)
### 3. Configure ESLint parsers
Depending on the languages you are using in your project you must tell which parser will analyze your source files.
Our recommendations:
#### For `.eslintrc`
- For `js[x]`, `react`, `ts[x]`:
- Install the parser: `npm i -D @typescript-eslint/parser`
- Assign it to your files in `eslintrc`:
```json5
overrides: [
{
files: ['*.ts', '*.tsx', '*.js'],
parser: '@typescript-eslint/parser',
},
],
```
- For `vue.js`:
- Install the parser: `npm i -D vue-eslint-parser`
- Assign it to your files in `eslintrc`:
```json5
overrides: [
{
files: ['*.vue'],
parser: 'vue-eslint-parser',
},
],
```
- For `HTML` and similar:
- Install the parser: `npm i -D @angular-eslint/template-parser`
- Assign it to your files in `eslintrc`:
```json5
overrides: [
{
files: ['*.html', '*.blade.php'],
parser: '@angular-eslint/template-parser',
},
],
```
> We removed the default parsers which were added to `v3.8.2` because it created negative impact on dependencies resolution, bundle size increase and possible conflicts with existing configurations.
#### For `eslint.config.js`
- For `js[x]`, `ts[x]`:
- Install the parser: `npm i -D @eslint/js typescript-eslint`
- Assign it to your files in `eslint.config.js`:
```js
import js from "@eslint/js";
import ts from "typescript-eslint";
import tailwind from "eslint-plugin-tailwindcss";
export default [
// add eslint built-in
js.configs.recommended,
// add `typescript-eslint` flat config simply
// if you would like use more another configuration,
// see the section: https://typescript-eslint.io/getting-started#details
...ts.configs.recommended,
...tailwind.configs["flat/recommended"],
];
```
- For `vue.js`:
- Install the parser: `npm i -D eslint-plugin-vue`
- Assign it to your files in `eslint.config.js`:
```js
import vue from "eslint-plugin-vue";
import tailwind from "eslint-plugin-tailwindcss";
export default [
// add `eslint-plugin-vue` flat config simply
// if you would like use more another configuration,
// see the section: https://eslint.vuejs.org/user-guide/#bundle-configurations-eslint-config-js
...vue.configs["flat/recommended"],
...tailwind.configs["flat/recommended"],
];
```
### 4. Add a npm script
In your `package.json` add one or more script(s) to run eslint targeting your source files:
```json5
"scripts": {
"lint": "eslint ./src",
"lint:debug": "eslint ./src --debug",
"lint:fix": "eslint ./src --fix"
},
```
### 5. Run the linting task
`npm run lint` can do the job on demand but you can also get live feedback using [VS Code ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint), **just make sure you restart VS Code** as it can be required for the plugin to work as expected.
## More settings
The rules accept settings meant to fit your own choices, make sure to read the [documentation of each rule](https://github.com/francoismassart/eslint-plugin-tailwindcss/tree/master/docs/rules).
### Optional shared settings
Most rules share the same settings, instead of duplicating the options all over the place...
You should define the [shared settings](https://eslint.org/docs/user-guide/configuring#adding-shared-settings) that will be shared across all the plugin rules.
All these settings already have nice default values that are explained in the documentation.
#### For `.eslintrc`
FYI, here are the `default` values:
```json5
{
settings: {
tailwindcss: {
// These are the default values but feel free to customize
callees: ["classnames", "clsx", "ctl"],
config: "tailwind.config.js", // returned from `loadConfig()` utility if not provided
cssFiles: [
"**/*.css",
"!**/node_modules",
"!**/.*",
"!**/dist",
"!**/build",
],
cssFilesRefreshRate: 5_000,
removeDuplicates: true,
skipClassAttribute: false,
whitelist: [],
tags: [], // can be set to e.g. ['tw'] for use in tw`bg-blue`
classRegex: "^class(Name)?$", // can be modified to support custom attributes. E.g. "^tw$" for `twin.macro`
},
},
}
```
#### For `eslint.config.js`
```js
import tailwind from "eslint-plugin-tailwindcss";
export default [
...tailwind.configs["flat/recommended"],
{
settings: {
tailwindcss: {
// These are the default values but feel free to customize
callees: ["classnames", "clsx", "ctl"],
config: "tailwind.config.js", // returned from `loadConfig()` utility if not provided
cssFiles: [
"**/*.css",
"!**/node_modules",
"!**/.*",
"!**/dist",
"!**/build",
],
cssFilesRefreshRate: 5_000,
removeDuplicates: true,
skipClassAttribute: false,
whitelist: [],
tags: [], // can be set to e.g. ['tw'] for use in tw`bg-blue`
classRegex: "^class(Name)?$", // can be modified to support custom attributes. E.g. "^tw$" for `twin.macro`
},
},
},
];
```
The plugin will look for each setting in this order and stops searching as soon as it finds the settings:
1. In the rule option argument (rule level)
2. In the shared settings (plugin level)
3. Default value of the requested setting (plugin level)...
## Upcoming Rules
- `validate-modifiers`: I don't know if possible, but I'd like to make sure all the modifiers prefixes of a classname are valid e.g. `yolo:bg-red` should throw an error...
- `no-redundant-variant`: e.g. avoid `mx-5 sm:mx-5`, no need to redefine `mx` in `sm:` variant as it uses the same value (`5`)
- `only-valid-arbitrary-values`:
- e.g. avoid `top-[42]`, only `0` value can be unitless.
- e.g. avoid `text-[rgba(10%,20%,30,50%)]`, can't mix `%` and `0-255`.
<!-- end auto-generated rules list -->
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚑️ by Socket Inc