eslint-plugin-css-property-order
v1.0.0
Published
ESLint plugin enforcing CSS declaration order for @eslint/css: Recess/Bootstrap logical order, Chrome DevTools panel order, or your own.
Maintainers
Readme
eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order for @eslint/css: Recess/Bootstrap logical order, Chrome DevTools panel order, alphabetical, or your own. Autofixable. Includes processors to lint and fix CSS embedded in HTML <style> tags and in /* css */-annotated or css-tagged template literals.
Installation
npm install -D eslint-plugin-css-property-order @eslint/cssUsage
// eslint.config.js
import { defineConfig } from "eslint/config";
import css from "@eslint/css";
import cssPropertyOrder from "eslint-plugin-css-property-order";
export default defineConfig([
{
files: ["**/*.css"],
plugins: { css },
language: "css/css",
extends: [cssPropertyOrder.configs.recommended],
},
]);[!NOTE] Use
extends(or a separate config object) rather than spreadingconfigs.recommendedinto an object that also declaresplugins: the spread would replace thepluginskey, unregistering thecssplugin thatlanguage: "css/css"refers to.
Run eslint --fix to reorder declarations automatically.
Built-in orders
"recess"(default, used byconfigs.recommended): the Recess/Bootstrap "logical" order — positioning, box model, typography, visual, animation, misc. Snapshot of stylelint-config-recess-order."devtools"(used byconfigs.devtools): the order Chrome DevTools shows in the Computed panel's grouped view — Layout, Text, Appearance, Animation, Grid, Table, Generated Content — generated from the DevTools sources themselves (PropertyNameCategories.ts+ Blink's property metadata)."alphabetical"(used byconfigs.alphabetical): plain alphabetical order. No property list is involved — names are compared directly, so every CSS property (present and future, standard or not) is covered and theunspecifiedoption does not apply. Vendor-prefixed properties sort right before their unprefixed counterpart (-webkit-transformbeforetransform), the order the cascade requires for fallbacks; custom properties are alphabetized at the top.
Options
{
files: ["**/*.css"],
plugins: { css, "css-property-order": cssPropertyOrder },
language: "css/css",
rules: {
"css-property-order/property-order": [
"error",
{
// "recess", "devtools", or an array of property names and/or
// { properties: [...] } groups:
order: "recess",
// Where properties absent from the order belong — "ignore" (leave
// them where they are), "top", "bottom", or "bottomAlphabetical".
// New CSS properties degrade gracefully: they are simply unspecified
// until the order lists them.
unspecified: "ignore",
// Custom properties (--*) must come first ("top", default) or are
// left alone ("ignore"). Their relative order is preserved.
customProperties: "top",
},
],
},
}Embedded CSS: HTML <style> tags and template literals
@eslint/css only lints .css files (HTML support is "not planned"). This plugin bridges the gap with two ESLint processors that extract embedded CSS into virtual *.css files — so your whole files: ["**/*.css"] config applies to them, every @eslint/css rule included, with autofix mapped back into the host file:
// eslint.config.js
export default defineConfig([
// Your CSS config lints the extracted blocks too:
{
files: ["**/*.css"],
plugins: { css },
language: "css/css",
extends: [cssPropertyOrder.configs.recommended],
},
// <style> tags in HTML files:
{
files: ["**/*.html"],
plugins: { "css-property-order": cssPropertyOrder },
processor: "css-property-order/html",
},
// /* css */ `…` and css`…` template literals in JS/TS files:
{
files: ["**/*.js"],
plugins: { "css-property-order": cssPropertyOrder },
processor: "css-property-order/tagged-template",
},
]);Both processors have factories for options (import them from the package):
createTaggedTemplateProcessor({ tags: ["css"], emitSource: true })—tagssets which template tags mark CSS (the/* css */comment form is always recognised);emitSource(default on) re-emits the JS/TS source so regular JavaScript linting keeps running on the file.createHtmlProcessor({ emitSource: false })— enableemitSourceonly if something else handles your HTML files — an HTML language config (e.g. html-eslint) or eslint-plugin-html for<script>linting — so it keeps linting them; without one the re-emitted source would be parsed as JavaScript.
Extraction limits (by design): template literals containing ${} substitutions or backslash escapes are skipped (their runtime value differs from the source, so fixes could not be mapped safely); HTML extraction is regex-based and ignores <style> inside comments and scripts; type-aware TypeScript linting does not work on processor virtual files (an ESLint-wide limitation).
Behavior notes
- Declarations are only reordered within a contiguous run: nested rules and at-rules act as boundaries, so a fix never moves a declaration across a nested rule (which could change the cascade).
- Comments are left in place; declarations move around them.
- Matching is case-insensitive; duplicate properties keep their relative order.
Updating the built-in orders
npm run generate:refresh re-downloads the DevTools sources (vendored in vendor/, provenance recorded in the generated files) and re-snapshots the Recess order, so newly shipped CSS properties flow into src/orders/.
npm run report:w3c compares the list-based presets against the official W3C CSS property index and reports which specified properties they do not list (those fall back to the unspecified option at lint time). The index spans every spec at every maturity level, so the report is informational — presets are never amended from it.
API
Modules
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_">eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders:
recess(default): the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools: the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.
Functions
Typedefs
<a name="eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_">
eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders:
recess(default): the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools: the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.
- [eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders:
recess(default): the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools: the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.](#eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_)- [~PropertyGroup](#eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_..PropertyGroup) : object- [~PropertyOrderEntry](#eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_..PropertyOrderEntry) : string | module:eslint~PropertyGroup- [~CustomPropertyOrder](#eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_..CustomPropertyOrder) : Array.<module:eslint~PropertyOrderEntry>- [~PropertyOrder](#eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_..PropertyOrder) : "devtools" | "recess" | "alphabetical" | module:eslint~CustomPropertyOrder- [~PropertyOrderRuleOptions](#eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_..PropertyOrderRuleOptions) : object
<a name="eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_..PropertyGroup">
eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders:
- `recess` (default): the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.
- `devtools`: the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.~PropertyGroup : object A named group of properties within a custom order. Group boundaries have no effect on ordering; they only help organising the list.
Kind: inner typedef of [eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders:
- `recess` (default): the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.
- `devtools`: the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.](#eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_) Properties
| Name | Type | Description | | ---------- | --------------------------------- | -------------------------------------------- | | [name] | string | Group name, for documentation purposes only. | | properties | Array.<string> | Property names in the group. |
<a name="eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_..PropertyOrderEntry">
eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders:
- `recess` (default): the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.
- `devtools`: the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.~~PropertyOrderEntry : string | module:eslint~~PropertyGroup One entry of a custom order: a property name, or a group of property names.
Kind: inner typedef of [eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders:
- `recess` (default): the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.
- `devtools`: the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.](#eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_) <a name="eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_..CustomPropertyOrder">
eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders:
- `recess` (default): the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.
- `devtools`: the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.~~CustomPropertyOrder : Array.<module:eslint~~PropertyOrderEntry> A custom order: an array of property names and/or groups of property names.
Kind: inner typedef of [eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders:
- `recess` (default): the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.
- `devtools`: the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.](#eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_) <a name="eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_..PropertyOrder">
eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders:
- `recess` (default): the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.
- `devtools`: the order Chrome DevTools uses in the Computed panels
grouped view, generated from the DevTools sources.~~PropertyOrder : "devtools" | "recess" | "alphabetical" | module:eslint~~CustomPropertyOrder
A built-in order name, or a custom order (see module:eslint~CustomPropertyOrder).
"alphabetical"needs no property list: it compares names directly (vendor-prefixed properties sort right before their unprefixed counterpart, as the cascade requires), so it covers every CSS property, present and future, andunspecifieddoes not apply.
Kind: inner typedef of [eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders:
- `recess` (default): the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.
- `devtools`: the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.](#eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_) <a name="eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_..PropertyOrderRuleOptions">
eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders:
- `recess` (default): the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.
- `devtools`: the order Chrome DevTools uses in the Computed panels
grouped view, generated from the DevTools sources.~PropertyOrderRuleOptions : object
Options for the
css-property-order/property-orderrule.
Kind: inner typedef of [eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders:
- `recess` (default): the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.
- `devtools`: the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.](#eslint-plugin-css-property-order
ESLint plugin enforcing CSS declaration order, for use with the official @eslint/css language plugin.
Ships two built-in orders_
recess(default)_ the Recess/Bootstrap logical order — positioning, box model, typography, visual, animation, misc.devtools_ the order Chrome DevTools uses in the Computed panels grouped view, generated from the DevTools sources.module_) Properties
| Name | Type | Default | Description |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [order] | module:eslint~PropertyOrder | "recess" | The property order to enforce. |
| [unspecified] | "ignore" | "top" | "bottom" | "bottomAlphabetical" | "ignore" | Where properties absent from the order (e.g. newer than the list) belong: left where they are, before all listed properties, after them (keeping their relative order), or after them alphabetically. |
| [customProperties] | "top" | "ignore" | "top" | Whether custom properties (--*) must come first in a block (keeping their relative order), or are left where they are. |
remapFix(fix, offset) ⇒ object
Kind: global function Returns: object - The remapped fix
| Param | Type | Description | | ------ | ------------------- | ------------------------------- | | fix | object | An ESLint fix ({ range, text }) | | offset | number | Host-file offset of the block |
remapMessage(message, offset, lineOffset, columnOffset) ⇒ object
Maps a lint message from block coordinates to host-file coordinates.
Kind: global function Returns: object - The remapped message
| Param | Type | Description | | ------------ | ------------------- | ------------------------------------------ | | message | object | An ESLint message | | offset | number | Host-file offset of the block | | lineOffset | number | Lines before the block in the host file | | columnOffset | number | Column of the block start on its host line |
createExtractionProcessor(options) ⇒ object
Creates an ESLint processor extracting CSS blocks from a host file.
Kind: global function Returns: object - An ESLint processor
| Param | Type | Description | | ------------------ | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | options | object | | | options.name | string | Processor name (for meta) | | options.extract | function | Finds CSS blocks | | options.emitSource | boolean | Whether to re-emit the host file as a bare-string block, linted under the host filename so its own language (or a patching plugin such as eslint-plugin-html) keeps linting it. Enable only when some config handles the host file as non-CSS. |
preprocess(text, filename) ⇒ Array.<VirtualFile>
Kind: global function Returns: Array.<VirtualFile> - Virtual files
| Param | Type | Description | | -------- | ------------------- | ----------------- | | text | string | Host file content | | filename | string | Host file path |
postprocess(messageLists, filename) ⇒ Array.<object>
Kind: global function Returns: Array.<object> - Messages mapped to host-file coordinates
| Param | Type | Description | | ------------ | ----------------------------------------------- | ------------------------- | | messageLists | Array.<Array.<object>> | One list per virtual file | | filename | string | Host file path |
extractStyleTags(text) ⇒ Array.<ExtractedBlock>
Kind: global function
| Param | Type | Description | | ----- | ------------------- | ----------- | | text | string | HTML source |
createHtmlProcessor([options]) ⇒ object
Creates the HTML processor.
Kind: global function Returns: object - An ESLint processor
| Param | Type | Default | Description | | -------------------- | -------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [options] | object | | | | [options.emitSource] | boolean | false | Also re-emit the HTML source so whatever handles the host file (an HTML language config, or a patching plugin such as eslint-plugin-html) keeps linting it. Leave off unless such a config exists: the source would otherwise be parsed as JavaScript. |
skipString(text, start) ⇒ number
Kind: global function Returns: number - Index after the closing quote (or line end if unterminated)
| Param | Type | Description | | ----- | ------------------- | -------------------------- | | text | string | Source | | start | number | Index of the opening quote |
skipTemplate(text, start) ⇒ TemplateSpan
Kind: global function
| Param | Type | Description | | ----- | ------------------- | ----------------------------- | | text | string | Source | | start | number | Index of the opening backtick |
skipSubstitution(text, start) ⇒ number
Kind: global function Returns: number - Index after the matching "}"
| Param | Type | Description | | ----- | ------------------- | ---------------- | | text | string | Source | | start | number | Index after "${" |
extractCssTemplates(text, tags) ⇒ Array.<ExtractedBlock>
Kind: global function
| Param | Type | Description | | ----- | --------------------------------- | -------------------------------- | | text | string | JavaScript/TypeScript source | | tags | Array.<string> | Template tag names that mark CSS |
createTaggedTemplateProcessor([options]) ⇒ object
Creates the tagged-template processor.
Kind: global function Returns: object - An ESLint processor
| Param | Type | Default | Description |
| -------------------- | --------------------------------- | ------------------------------ | -------------------------------------------------------------------------------------- |
| [options] | object | | |
| [options.tags] | Array.<string> | ["css"] | Template tag names to extract. The \/* css *\/ comment form is always recognised. |
| [options.emitSource] | boolean | true | Also re-emit the JS/TS source so regular JavaScript linting keeps running on the file. |
alphabeticalKey(name) ⇒ [string, number, string]
Alphabetical sort key: compares on the unprefixed name, with prefixed variants right before their unprefixed property ("-webkit-transform" before "transform"), matching the fallback order the cascade requires.
Kind: global function
| Param | Type | Description | | ----- | ------------------- | ------------------------ | | name | string | Lowercased property name |
createOrderIndex(order) ⇒ Map.<string, number>
Flattens an order option into a property → index map.
Kind: global function
| Param | Type | | ----- | -------------------------- | | order | PropertyOrder |
isCustomProperty(decl) ⇒ boolean
Kind: global function
| Param | Type | Description | | ----- | ------------------- | ------------------ | | decl | object | A Declaration node |
ExtractedBlock : object
A CSS segment found in a host file.
Kind: global typedef Properties
| Name | Type | Description | | ------ | ------------------- | --------------------------------------------- | | offset | number | Start offset of the CSS text in the host file | | text | string | The CSS text, verbatim |
VirtualFile : object
A virtual file emitted for a host file, as ESLint's processor API expects.
Kind: global typedef Properties
| Name | Type | Description | | -------- | ------------------- | -------------------- | | text | string | The file content | | filename | string | The virtual filename |
TemplateSpan : object
Kind: global typedef Properties
| Name | Type | Description | | ----- | -------------------- | -------------------------------------------------------------------- | | end | number | Index after the closing backtick | | clean | boolean | Whether the template body is verbatim CSS (no substitutions/escapes) |
NumberOrString : number | string
Kind: global typedef
SortKey : Array.<NumberOrString>
A declaration's ordering key: tier first, then tiebreakers, compared element-wise against another key of the same shape.
Kind: global typedef
License
MIT. See license file.
