The PostCSS node tree
PostCSS turns a stylesheet into a tree of typed nodes. A Root contains
Rule and AtRule children; rules and at-rules contain Declaration and
Comment nodes. Plugins walk this tree, read properties like selector,
prop and value, and mutate or replace nodes — then PostCSS stringifies the
tree back to CSS. This reference lists each built-in node type and the API you
use to transform it.
How it works
Every node carries a type string and links to its parent. Containers
(Root, Rule, AtRule) hold a nodes array of children and expose walk*
helpers to traverse them:
module.exports = () => ({
postcssPlugin: "demo",
Once(root, { Declaration }) {
root.walkDecls("color", (decl) => {
if (decl.value === "red") decl.value = "#f00";
});
root.walkAtRules("media", (atRule) => {
// atRule.name === "media", atRule.params === "(min-width: 768px)"
});
},
});
module.exports.postcss = true;
Walk callbacks run depth-first. Returning nothing continues; calling
decl.remove() or rule.replaceWith(...) mutates the tree in place.
Tips and notes
- Prefer the visitor API (
Declaration(decl, helpers)) overOnce+walk*for plugins that compose well — PostCSS batches a single AST pass. - Use
node.clone()before reusing a node elsewhere; nodes can only have one parent. decl.importantis a boolean, not part ofvalue; preserve it when rewriting.atRule.nodesisundefinedfor statement at-rules like@import, and an array for block at-rules like@media.