PostCSS plugin and Node.js module that sorts CSS declarations automatically based on their property names.
npx @tessl/cli install tessl/npm-css-declaration-sorter@7.2.0CSS Declaration Sorter is a Node.js module and PostCSS plugin that automatically sorts CSS, SCSS, or Less declarations based on their property names. It ensures consistent styling organization and can reduce distributed CSS gzipped size through thoughtful property ordering.
npm install postcss css-declaration-sorterESM (ES Modules):
import { cssDeclarationSorter } from "css-declaration-sorter";
// or
import cssDeclarationSorter from "css-declaration-sorter";CommonJS:
const cssDeclarationSorter = require("css-declaration-sorter");
// or
const { cssDeclarationSorter } = require("css-declaration-sorter");import postcss from "postcss";
import { cssDeclarationSorter } from "css-declaration-sorter";
// Basic usage with default alphabetical sorting
const result = await postcss([cssDeclarationSorter()])
.process(css, { from: undefined });
// With options
const result = await postcss([
cssDeclarationSorter({
order: 'smacss',
keepOverrides: true
})
]).process(css, { from: undefined });Input CSS:
body {
display: block;
animation: none;
color: #C55;
border: 0;
}Output CSS (alphabetical order):
body {
animation: none;
border: 0;
color: #C55;
display: block;
}CSS Declaration Sorter is built around several key components:
Creates a PostCSS plugin instance that sorts CSS declarations.
/**
* Creates a PostCSS plugin that sorts CSS declarations
* @param options - Configuration options for sorting behavior
* @returns PostCSS plugin object with postcssPlugin property and OnceExit method
*/
function cssDeclarationSorter(options?: {
order?: SortOrder | SortFunction;
keepOverrides?: boolean;
}): {
postcssPlugin: 'css-declaration-sorter';
OnceExit(root: Root): void | Promise<void>;
};
// Available as both named export and default export
export { cssDeclarationSorter };
export default cssDeclarationSorter;The plugin accepts an options object with the following properties:
interface PluginOptions {
/**
* Provide the name of one of the built-in sort orders or a comparison function
* @default 'alphabetical'
*/
order?: SortOrder | SortFunction;
/**
* Prevent breaking legacy CSS where shorthand declarations override longhand declarations
* @default false
*/
keepOverrides?: boolean;
}
type SortOrder = 'alphabetical' | 'concentric-css' | 'smacss';
/**
* Custom comparison function for sorting CSS properties
* @param propertyNameA - First property name to compare
* @param propertyNameB - Second property name to compare
* @returns -1, 0, or 1 indicating sort order
*/
type SortFunction = (propertyNameA: string, propertyNameB: string) => -1 | 0 | 1;The plugin provides three built-in sorting orders:
Alphabetical ('alphabetical'):
SMACSS ('smacss'):
Concentric CSS ('concentric-css'):
You can provide a custom comparison function for advanced sorting logic:
import { cssDeclarationSorter } from "css-declaration-sorter";
// Custom sort function example
const plugin = cssDeclarationSorter({
order: (propA, propB) => {
// Custom logic: prioritize display properties
if (propA.startsWith('display')) return -1;
if (propB.startsWith('display')) return 1;
return propA.localeCompare(propB);
}
});The keepOverrides option prevents breaking CSS cascade rules where shorthand properties should override longhand properties:
import { cssDeclarationSorter } from "css-declaration-sorter";
const plugin = cssDeclarationSorter({
keepOverrides: true
});
// This preserves intentional override patterns:
// animation-name: fadeIn;
// animation: slideIn 1s ease; // This overrides animation-nameThe plugin validates built-in order names and rejects with descriptive errors during processing:
// Invalid order will cause processing to reject
try {
const result = await postcss([cssDeclarationSorter({ order: 'invalid-order' })])
.process(css, { from: undefined });
} catch (error) {
// Error message: "Invalid built-in order 'invalid-order' provided.
// Available built-in orders are: alphabetical,concentric-css,smacss"
}The plugin includes three built-in sorting orders as separate modules:
// Built-in order identifiers
const builtInOrders: readonly ['alphabetical', 'concentric-css', 'smacss'];The plugin uses an optimized bubble sort algorithm for in-place sorting of CSS declarations:
/**
* Optimized bubble sort implementation for CSS node arrays
* @param list - Array of PostCSS nodes to sort
* @param comparator - Comparison function for sorting
* @returns The sorted array (modified in-place)
*/
function bubbleSort<T>(list: T[], comparator: (a: T, b: T) => number): T[];When keepOverrides is enabled, the plugin uses shorthand data to prevent breaking CSS cascade rules:
/**
* Shorthand property data mapping shorthand properties to their longhand equivalents
* Used for override detection when keepOverrides is true
*/
interface ShorthandData {
[shorthandProperty: string]: string[];
}
// Example entries from shorthandData:
// 'animation': ['animation-name', 'animation-duration', 'animation-timing-function', ...]
// 'border': ['border-top', 'border-right', 'border-bottom', 'border-left', ...]
// 'margin': ['margin-top', 'margin-right', 'margin-bottom', 'margin-left', ...]The plugin integrates with PostCSS through the standard plugin interface:
interface PostCSSPlugin {
postcssPlugin: 'css-declaration-sorter';
OnceExit(root: Root): void | Promise<void>;
postcss: true; // Static property indicating PostCSS compatibility
}Usage with PostCSS configuration:
// postcss.config.js
module.exports = {
plugins: [
require('css-declaration-sorter')({
order: 'smacss'
})
]
};Usage with build tools:
// webpack.config.js with postcss-loader
module.exports = {
module: {
rules: [{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
['css-declaration-sorter', { order: 'alphabetical' }]
]
}
}
}
]
}]
}
};The plugin works with SCSS and Less when combined with appropriate PostCSS parsers:
import postcss from "postcss";
import postcssScss from "postcss-scss";
import { cssDeclarationSorter } from "css-declaration-sorter";
// SCSS support
const result = await postcss([cssDeclarationSorter()])
.process(scssContent, {
from: undefined,
parser: postcssScss
});The plugin intelligently handles CSS comments during the sorting process:
/* Input */
.example {
display: block;
/* This comment stays with color */
color: red;
border: 1px solid black;
}
/* Output (alphabetical) */
.example {
border: 1px solid black;
/* This comment stays with color */
color: red;
display: block;
}Vendor-prefixed properties are treated as their unprefixed equivalents for sorting:
/* Input */
.example {
display: block;
-webkit-transform: scale(1);
transform: scale(1);
color: red;
}
/* Output (alphabetical) */
.example {
color: red;
display: block;
-webkit-transform: scale(1);
transform: scale(1);
}Complete TypeScript definitions are provided for full type safety:
import type { PluginCreator, Root } from 'postcss';
// ESM type definitions (main.d.mts)
declare const cssDeclarationSorter: PluginCreator<{
order?: SortOrder | SortFunction | undefined;
keepOverrides?: boolean;
}>;
export { cssDeclarationSorter };
export default cssDeclarationSorter;
// CommonJS type definitions (main.d.cts)
// export = cssDeclarationSorter;
type SortOrder = 'alphabetical' | 'concentric-css' | 'smacss';
/**
* Custom comparison function for sorting CSS properties
* @param propertyNameA - First property name to compare
* @param propertyNameB - Second property name to compare
* @returns -1, 0, or 1 indicating sort order
*/
type SortFunction = (propertyNameA: string, propertyNameB: string) => -1 | 0 | 1;
interface PluginOptions {
/**
* Provide the name of one of the built-in sort orders or a comparison function
* @default 'alphabetical'
*/
order?: SortOrder | SortFunction;
/**
* Prevent breaking legacy CSS where shorthand declarations override longhand declarations
* @default false
*/
keepOverrides?: boolean;
}import postcss from "postcss";
import { cssDeclarationSorter } from "css-declaration-sorter";
// Apply different sorting to different selectors
const processor = postcss([
cssDeclarationSorter({ order: 'smacss' })
]);
const css = `
.layout { position: relative; display: flex; margin: 10px; }
.text { font-size: 16px; color: blue; line-height: 1.4; }
`;
const result = await processor.process(css, { from: undefined });// Works well with CSS frameworks and methodologies
const plugin = cssDeclarationSorter({
order: 'concentric-css', // Matches BEM/OOCSS patterns
keepOverrides: true // Preserves framework override patterns
});// gulpfile.js
import gulp from 'gulp';
import postcss from 'gulp-postcss';
import { cssDeclarationSorter } from 'css-declaration-sorter';
gulp.task('css', () => {
return gulp.src('src/**/*.css')
.pipe(postcss([
cssDeclarationSorter({ order: 'alphabetical' })
]))
.pipe(gulp.dest('dist/'));
});