Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Your own plugin in five minutes

A PostCSS plugin is an ordinary JavaScript function that returns an object with a name and handlers — functions PostCSS calls for tree nodes: for every rule, every property and so on. Writing your own plugin is easier than it looks, and it is the best way to understand how the others work.

The task

The blog styles must not contain !important: it breaks the normal order in which rules apply. Let us write a plugin that removes !important and warns about it in the terminal.

The plugin code

Create a plugins/ folder in the project root and the file plugins/no-important.js:

// plugins/no-important.js
const noImportant = () => {
  return {
    postcssPlugin: 'no-important',
    Declaration(decl, { result }) {
      if (decl.important) {
        decl.warn(result, `Removed !important from ${decl.prop}`);
        decl.important = false;
      }
    },
  };
};
 
noImportant.postcss = true;
 
export default noImportant;

Line by line:

LineMeaning
postcssPluginThe plugin name, shown in messages
DeclarationCalled for every property: value declaration
decl.importanttrue if the declaration has !important
decl.warnAdds a warning with a line number
noImportant.postcss = trueThe mark by which PostCSS recognizes a plugin

Adding it

Import the plugin by relative path, like any module:

// postcss.config.js
import postcssPresetEnv from 'postcss-preset-env';
import noImportant from './plugins/no-important.js';
 
export default {
  plugins: [noImportant(), postcssPresetEnv()],
};

Try it on a file with !important:

/* styles/main.css */
.post-title {
  color: #1e293b !important;
  margin: 0;
}

After npx postcss styles/main.css -o css/main.css the terminal shows a warning with its position — line 2, column 3:

2:3  ⚠  Removed !important from color [no-important]

And in css/main.css:

.post-title {
  color: #1e293b;
  margin: 0;
}

Other handlers

HandlerWhen it is called
Once(root)Once for the whole file
Rule(rule)For every rule with a selector, rule.selector
AtRule(atRule)For every at-rule like @media, atRule.name
Declaration(decl)For every declaration, decl.prop and decl.value

You can give Declaration an object keyed by property names — then the function runs only for them, for example Declaration: { color: (decl) => ... }.

Common mistake

Removing the noImportant.postcss = true line and adding the plugin without a call — noImportant instead of noImportant(). Without the mark, PostCSS treats the function as an old-style plugin, calls it with the tree and throws away the returned object with handlers. There is no error, but !important stays in place. Keep the postcss mark in the plugin file and call the plugin with parentheses in the config, like the other plugins.

Thanks for reading!

Donate to the site — we work hard for you.