@eslint/css
Version:
CSS linting plugin for ESLint
299 lines (230 loc) • 12.4 kB
Markdown
# ESLint CSS Language Plugin
## Overview
This package contains a plugin that allows you to natively lint CSS files using ESLint.
**Important:** This plugin requires ESLint v9.6.0 or higher and you must be using the [new configuration system](https://eslint.org/docs/latest/use/configure/configuration-files).
## Prequisites
In order to use the ESLint CSS plugin, you must have the following installed:
1. [Node.js](https://nodejs.org)
1. [ESLint](https://eslint.org/docs/latest/use/getting-started)
## Installation
For Node.js and compatible runtimes:
```shell
npm install @eslint/css -D
# or
yarn add @eslint/css -D
# or
pnpm install @eslint/css -D
# or
bun add @eslint/css -D
```
For Deno (experimental):
```shell
deno add jsr:@eslint/css
```
### Configurations
| **Configuration Name** | **Description** |
| ---------------------- | ------------------------------ |
| `recommended` | Enables all recommended rules. |
In your `eslint.config.js` file, import `@eslint/css` and include the recommended config:
```js
// eslint.config.js
import { defineConfig } from "eslint/config";
import css from "@eslint/css";
export default defineConfig([
// lint CSS files
{
files: ["**/*.css"],
language: "css/css",
plugins: { css },
extends: ["css/recommended"],
},
// your other configs here
]);
```
### Rules
<!-- NOTE: The following table is autogenerated. Do not manually edit. -->
<!-- Rule Table Start -->
| **Rule Name** | **Description** | **Recommended** |
| :----------------------------------------------------------------------------------- | :---------------------------------------------------- | :-------------: |
| [`font-family-fallbacks`](./docs/rules/font-family-fallbacks.md) | Enforce use of fallback fonts and a generic font last | yes |
| [`no-duplicate-imports`](./docs/rules/no-duplicate-imports.md) | Disallow duplicate @import rules | yes |
| [`no-duplicate-keyframe-selectors`](./docs/rules/no-duplicate-keyframe-selectors.md) | Disallow duplicate selectors within keyframe blocks | yes |
| [`no-empty-blocks`](./docs/rules/no-empty-blocks.md) | Disallow empty blocks | yes |
| [`no-important`](./docs/rules/no-important.md) | Disallow !important flags | yes |
| [`no-invalid-at-rule-placement`](./docs/rules/no-invalid-at-rule-placement.md) | Disallow invalid placement of at-rules | yes |
| [`no-invalid-at-rules`](./docs/rules/no-invalid-at-rules.md) | Disallow invalid at-rules | yes |
| [`no-invalid-named-grid-areas`](./docs/rules/no-invalid-named-grid-areas.md) | Disallow invalid named grid areas | yes |
| [`no-invalid-properties`](./docs/rules/no-invalid-properties.md) | Disallow invalid properties | yes |
| [`prefer-logical-properties`](./docs/rules/prefer-logical-properties.md) | Enforce the use of logical properties | no |
| [`relative-font-units`](./docs/rules/relative-font-units.md) | Enforce the use of relative font units | no |
| [`use-baseline`](./docs/rules/use-baseline.md) | Enforce the use of baseline features | yes |
| [`use-layers`](./docs/rules/use-layers.md) | Require use of layers | no |
<!-- Rule Table End -->
**Note:** This plugin does not provide formatting rules. We recommend using a source code formatter such as [Prettier](https://prettier.io) for that purpose.
In order to individually configure a rule in your `eslint.config.js` file, import `@eslint/css` and configure each rule with a prefix:
```js
// eslint.config.js
import { defineConfig } from "eslint/config";
import css from "@eslint/css";
export default defineConfig([
{
files: ["**/*.css"],
plugins: {
css,
},
language: "css/css",
rules: {
"css/no-empty-blocks": "error",
},
},
]);
```
You can individually config, disable, and enable rules in CSS using comments, such as:
<!-- prettier-ignore -->
```css
/* eslint css/no-empty-blocks: error */
/* eslint-disable css/no-empty-blocks -- this one is ok */
a {
}
/* eslint-enable css/no-empty-blocks */
b { /* eslint-disable-line css/no-empty-blocks */
}
/* eslint-disable-next-line css/no-empty-blocks */
em {
}
```
### Languages
| **Language Name** | **Description** |
| ----------------- | ---------------------- |
| `css` | Parse CSS stylesheets. |
In order to individually configure a language in your `eslint.config.js` file, import `@eslint/css` and configure a `language`:
```js
// eslint.config.js
import { defineConfig } from "eslint/config";
import css from "@eslint/css";
export default defineConfig([
{
files: ["**/*.css"],
plugins: {
css,
},
language: "css/css",
rules: {
"css/no-empty-blocks": "error",
},
},
]);
```
#### Tolerant Mode
By default, the CSS parser runs in strict mode, which reports all parsing errors. If you'd like to allow recoverable parsing errors (those that the browser automatically fixes on its own), you can set the `tolerant` option to `true`:
```js
// eslint.config.js
import { defineConfig } from "eslint/config";
import css from "@eslint/css";
export default defineConfig([
{
files: ["**/*.css"],
plugins: {
css,
},
language: "css/css",
languageOptions: {
tolerant: true,
},
rules: {
"css/no-empty-blocks": "error",
},
},
]);
```
Setting `tolerant` to `true` is necessary if you are using custom syntax, such as [PostCSS](https://postcss.org/) plugins, that aren't part of the standard CSS syntax.
#### Configuring Custom Syntax
The CSS lexer comes prebuilt with a set of known syntax for CSS that is used in rules like `no-invalid-properties` to validate CSS code. While this works for most cases, there may be cases when you want to define your own extensions to CSS, and this can be done using the `customSyntax` language option.
The `customSyntax` option is an object that uses the [CSSTree format](https://github.com/csstree/csstree/blob/master/data/patch.json) for defining custom syntax, which allows you to specify at-rules, properties, and some types. For example, suppose you'd like to define a custom at-rule that looks like this:
```css
@my-at-rule "hello world!";
```
You can configure that syntax as follows:
```js
// eslint.config.js
import { defineConfig } from "eslint/config";
import css from "@eslint/css";
export default defineConfig([
{
files: ["**/*.css"],
plugins: {
css,
},
language: "css/css",
languageOptions: {
customSyntax: {
atrules: {
"my-at-rule": {
prelude: "<string>",
},
},
},
},
rules: {
"css/no-empty-blocks": "error",
},
},
]);
```
#### Configuring Tailwind Syntax
[Tailwind](https://tailwindcss.com) specifies some extensions to CSS that will otherwise be flagged as invalid by the rules in this plugin. To properly parse Tailwind-specific syntax, install the [`tailwind-csstree`](https://npmjs.com/package/tailwind-csstree) package:
```shell
npm i tailwind-csstree --save-dev
```
Then include it in your configuration using `languageOptions.customSyntax`:
```js
// eslint.config.js
import { defineConfig } from "eslint/config";
import css from "@eslint/css";
import { tailwind4 } from "tailwind-csstree";
export default defineConfig([
{
files: ["**/*.css"],
plugins: {
css,
},
language: "css/css",
languageOptions: {
customSyntax: tailwind4,
},
rules: {
"css/no-empty-blocks": "error",
},
},
]);
```
## Editor and IDE Setup
### Visual Studio Code
First, ensure you have the [ESLint plugin](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) installed.
Then, edit `eslint.validate` in your `settings.json` file to include `css`:
```json
{
"eslint.validate": ["css"]
}
```
### JetBrains WebStorm
For any [JetBrains WebStorm](https://www.jetbrains.com/webstorm/), configure the [ESLint scope](https://www.jetbrains.com/help/webstorm/eslint.html#ws_eslint_configure_scope) to include `css`, such as:
```text
**/*.{js,ts,jsx,tsx,cjs,cts,mjs,mts,html,vue,css}
```
## License
Apache 2.0
<!-- NOTE: This section is autogenerated. Do not manually edit.-->
<!--sponsorsstart-->
## Sponsors
The following companies, organizations, and individuals support ESLint's ongoing maintenance and development. [Become a Sponsor](https://eslint.org/donate)
to get your logo on our READMEs and [website](https://eslint.org/sponsors).
<h3>Platinum Sponsors</h3>
<p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="128"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="128"></a></p><h3>Gold Sponsors</h3>
<p><a href="https://qlty.sh/"><img src="https://images.opencollective.com/qltysh/33d157d/logo.png" alt="Qlty Software" height="96"></a> <a href="https://trunk.io/"><img src="https://images.opencollective.com/trunkio/fb92d60/avatar.png" alt="trunk.io" height="96"></a> <a href="https://shopify.engineering/"><img src="https://avatars.githubusercontent.com/u/8085" alt="Shopify" height="96"></a></p><h3>Silver Sponsors</h3>
<p><a href="https://vite.dev/"><img src="https://images.opencollective.com/vite/e6d15e1/logo.png" alt="Vite" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301" alt="American Express" height="64"></a> <a href="https://stackblitz.com"><img src="https://avatars.githubusercontent.com/u/28635252" alt="StackBlitz" height="64"></a></p><h3>Bronze Sponsors</h3>
<p><a href="https://cybozu.co.jp/"><img src="https://images.opencollective.com/cybozu/933e46d/logo.png" alt="Cybozu" height="32"></a> <a href="https://sentry.io"><img src="https://github.com/getsentry.png" alt="Sentry" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://icons8.com/"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://www.gitbook.com"><img src="https://avatars.githubusercontent.com/u/7111340" alt="GitBook" height="32"></a> <a href="https://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104" alt="Nx" height="32"></a> <a href="https://opensource.mercedes-benz.com/"><img src="https://avatars.githubusercontent.com/u/34240465" alt="Mercedes-Benz Group" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774" alt="HeroCoders" height="32"></a> <a href="https://www.lambdatest.com"><img src="https://avatars.githubusercontent.com/u/171592363" alt="LambdaTest" height="32"></a></p>
<h3>Technology Sponsors</h3>
Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.
<p><a href="https://netlify.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/netlify-icon.svg" alt="Netlify" height="32"></a> <a href="https://algolia.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/algolia-icon.svg" alt="Algolia" height="32"></a> <a href="https://1password.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/1password-icon.svg" alt="1Password" height="32"></a></p>
<!--sponsorsend-->