PostCSS plugin that enables CSS nesting functionality following the CSS Nesting specification
npx @tessl/cli install tessl/npm-postcss-nesting@13.0.0PostCSS Nesting is a PostCSS plugin that enables CSS nesting functionality, allowing developers to nest style rules inside each other following the CSS Nesting specification. It transforms nested CSS into standard CSS that browsers can understand, providing Sass-like nesting capabilities while adhering to web standards.
npm install postcss-nesting --save-devpostcss ^8.4 (install separately: npm install postcss --save-dev)import postcssNesting from "postcss-nesting";For CommonJS:
const postcssNesting = require("postcss-nesting");import postcss from "postcss";
import postcssNesting from "postcss-nesting";
// Basic usage with default 2024-02 edition
const processor = postcss([
postcssNesting()
]);
const result = await processor.process(css, { from: "input.css", to: "output.css" });
// With options (2021 edition supports options)
const processorWithOptions = postcss([
postcssNesting({
edition: '2021',
noIsPseudoSelector: true,
silenceAtNestWarning: true
})
]);
// Note: 2024-02 edition ignores options except 'edition'
const processor2024 = postcss([
postcssNesting({
edition: '2024-02'
// Other options are ignored in 2024-02 edition
})
]);Example CSS transformation:
/* Input */
.foo {
color: red;
&:hover {
color: green;
}
> .bar {
color: blue;
}
@media (prefers-color-scheme: dark) {
color: cyan;
}
}
/* Output (2024-02 edition) */
.foo {
color: red;
}
.foo:hover {
color: green;
}
.foo > .bar {
color: blue;
}
@media (prefers-color-scheme: dark) {
.foo {
color: cyan;
}
}Creates a postcss-nesting plugin instance with specified options.
/**
* Creates a postcss-nesting plugin instance
* @param opts - Plugin configuration options
* @returns PostCSS plugin instance
*/
function postcssNesting(opts?: pluginOptions): PostCSSPlugin;
// Returns a PostCSS plugin object with the following structure:
// {
// postcssPlugin: 'postcss-nesting',
// Rule(rule, { result }) { /* processing logic */ },
// AtRule?: { nest(rule) { /* @nest handling */ } }
// }The plugin function has a postcss property set to true to indicate PostCSS compatibility:
postcssNesting.postcss = true;Configuration options for the postcss-nesting plugin.
interface pluginOptions {
/** The implementation edition for CSS Nesting, defaults to '2024-02' */
edition?: '2021' | '2024-02';
/** Avoid the :is() pseudo class (2021 edition only) */
noIsPseudoSelector?: boolean;
/** Silence the @nest warning (2021 edition only) */
silenceAtNestWarning?: boolean;
}Options available for the 2021 edition:
interface pluginOptions2021 {
/** Avoid the :is() pseudo class as much as possible, default: false */
noIsPseudoSelector?: boolean;
/** Silence the @nest warning */
silenceAtNestWarning?: boolean;
}Options for the 2024-02 edition:
interface pluginOptions2024_02 {
/** @deprecated This option was removed. You must migrate your CSS to the latest specification to continue using this plugin. */
noIsPseudoSelector?: boolean;
}The plugin supports two specification editions with different behaviors:
The current specification implementation:
:is() pseudo-class in generated CSS (required for correct specificity)and keyword@nest syntax is removed and will throw an erroredition for switching between editions)postcssNesting({
edition: '2024-02' // default
})
// In 2024-02 edition, the plugin creator ignores options
postcssNesting() // equivalent to aboveLegacy specification implementation for backward compatibility:
:is() pseudo-class usage (can be disabled with noIsPseudoSelector)@nest syntax with optional warning suppressionpostcssNesting({
edition: '2021',
noIsPseudoSelector: true, // avoid :is() when possible
silenceAtNestWarning: true // suppress @nest warnings
})// Without noIsPseudoSelector (maintains specification compliance)
postcssNesting({ edition: '2021' })
// CSS Input:
// #alpha, .beta {
// &:hover { order: 1; }
// }
// Output: :is(#alpha,.beta):hover { order: 1; }
// With noIsPseudoSelector (non-standard specificity)
postcssNesting({
edition: '2021',
noIsPseudoSelector: true
})
// Same Input
// Output: #alpha:hover, .beta:hover { order: 1; }The plugin throws errors for invalid configurations:
// Invalid edition throws error
try {
postcssNesting({ edition: 'invalid' });
} catch (error) {
console.log(error.message); // "Invalid edition: invalid"
}
// @nest usage in 2024-02 edition throws error
// CSS: @nest .foo & { color: red; }
// Error: "`@nest` was removed from the CSS Nesting specification and will be removed from PostCSS Nesting in the next major version."Complete TypeScript type definitions are provided:
import type { PluginCreator } from 'postcss';
// Main plugin creator function
declare const creator: PluginCreator<pluginOptions>;
// Plugin creator has postcss property set to true
creator.postcss = true;
export default creator;
export declare type pluginOptions = {
edition?: '2021' | '2024-02';
} & pluginOptions2021 & pluginOptions2024_02;
export declare type pluginOptions2021 = {
noIsPseudoSelector?: boolean;
silenceAtNestWarning?: boolean;
};
export declare type pluginOptions2024_02 = {
/** @deprecated */
noIsPseudoSelector?: boolean;
};postcss input.css -o output.css -u postcss-nestingmodule.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('postcss-nesting')({
edition: '2024-02'
})
]
}
}
}
]
}
]
}
};// next.config.js
module.exports = {
webpack: (config) => {
config.module.rules.push({
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('postcss-nesting')()
]
}
}
}
]
});
return config;
}
};