PostCSS integration library for CSS-in-JS and JavaScript style objects with bidirectional conversion capabilities
npx @tessl/cli install tessl/npm-postcss-js@4.0.0PostCSS JS is a PostCSS integration library that enables the use of PostCSS plugins with CSS-in-JS and JavaScript style objects. It provides bidirectional conversion between CSS-in-JS objects and PostCSS AST, allowing developers to use the entire PostCSS ecosystem within JavaScript-based styling workflows.
npm install postcss-jspostcss@^8.4.21const postcssJs = require("postcss-js");
const { sync, async, parse, objectify } = require("postcss-js");For ES modules:
import postcssJs from "postcss-js";
import { sync, async, parse, objectify } from "postcss-js";Individual module imports:
const sync = require("postcss-js/sync");
const async = require("postcss-js/async");
const parse = require("postcss-js/parser");
const objectify = require("postcss-js/objectifier");const postcssJs = require("postcss-js");
const autoprefixer = require("autoprefixer");
// Create a synchronous processor
const prefixer = postcssJs.sync([autoprefixer]);
// Process CSS-in-JS objects
const style = prefixer({
userSelect: "none",
display: "flex"
});
// Result: {
// WebkitUserSelect: "none",
// MozUserSelect: "none",
// msUserSelect: "none",
// userSelect: "none",
// display: "flex"
// }
// Parse CSS-in-JS to PostCSS AST
const root = postcssJs.parse({
color: "red",
"&:hover": {
color: "blue"
}
});
// Convert PostCSS AST back to CSS-in-JS
const obj = postcssJs.objectify(root);PostCSS JS is built around four core components:
sync and async functions that create PostCSS processors for CSS-in-JS objectsparse function that converts CSS-in-JS objects to PostCSS ASTobjectify function that converts PostCSS AST back to CSS-in-JS objectsCreates a synchronous PostCSS processor that works with CSS-in-JS objects and supports only synchronous PostCSS plugins.
/**
* Create PostCSS processor with simple API, but with only sync PostCSS plugins support
* @param {Plugin[]} plugins - Array of PostCSS plugins (synchronous only)
* @returns {function} Processor function that takes a style object and returns processed object
*/
function sync(plugins);Usage Examples:
const postcssJs = require("postcss-js");
const autoprefixer = require("autoprefixer");
// Create processor with plugins
const processor = postcssJs.sync([autoprefixer]);
// Process style objects
const result = processor({
display: "flex",
userSelect: "none"
});Creates an asynchronous PostCSS processor that works with CSS-in-JS objects and supports both synchronous and asynchronous PostCSS plugins.
/**
* Create PostCSS processor that supports both sync and async plugins
* @param {Plugin[]} plugins - Array of PostCSS plugins (sync and async)
* @returns {function} Async processor function that takes a style object and returns Promise<object>
*/
function async(plugins);Usage Examples:
const postcssJs = require("postcss-js");
const autoprefixer = require("autoprefixer");
// Create async processor
const processor = postcssJs.async([autoprefixer]);
// Process style objects (returns Promise)
const result = await processor({
display: "flex",
userSelect: "none"
});Parses CSS-in-JS style objects into PostCSS Root instances, handling nested selectors, at-rules, and property conversions.
/**
* Parse CSS-in-JS style object to PostCSS Root instance
* @param {Object} obj - CSS-in-JS style object
* @returns {Root} PostCSS Root instance
*/
function parse(obj);Key Features:
userSelect → user-select)px suffix to numeric values (except for unitless properties)--variables) without name conversion, preserving exact syntax!important declarationsUsage Examples:
const postcss = require("postcss");
const postcssJs = require("postcss-js");
// Parse complex CSS-in-JS object
const root = postcssJs.parse({
color: "red",
fontSize: 16,
margin: [10, 20],
"--custom-prop": "#fff",
"&:hover": {
color: "blue"
},
"@media screen": {
fontSize: 18
}
});
// Use as PostCSS parser
const result = await postcss().process(styleObj, {
parser: postcssJs,
from: undefined
});Converts PostCSS Root instances back to CSS-in-JS style objects with proper property name and value conversions.
/**
* Convert PostCSS Root instance to CSS-in-JS style object
* @param {Root} root - PostCSS Root instance
* @returns {Object} CSS-in-JS style object
*/
function objectify(root);Key Features:
user-select → userSelect)--variables) without name conversion, preserving exact property names!important declarationsUsage Examples:
const postcss = require("postcss");
const postcssJs = require("postcss-js");
// Convert PostCSS AST to object
const css = "color: red; font-size: 16px; --theme-color: blue;";
const root = postcss.parse(css);
const obj = postcssJs.objectify(root);
// Result: {
// color: "red",
// fontSize: "16px",
// "--theme-color": "blue"
// }The following CSS properties are treated as unitless and numeric values are not converted to pixels. The parser uses kebab-case names while the objectifier uses camelCase names:
Parser (kebab-case):
const PARSER_UNITLESS = {
"box-flex": true,
"box-flex-group": true,
"column-count": true,
"flex": true,
"flex-grow": true,
"flex-positive": true,
"flex-shrink": true,
"flex-negative": true,
"font-weight": true,
"line-clamp": true,
"line-height": true,
"opacity": true,
"order": true,
"orphans": true,
"tab-size": true,
"widows": true,
"z-index": true,
"zoom": true,
"fill-opacity": true,
"stroke-dashoffset": true,
"stroke-opacity": true,
"stroke-width": true
};Objectifier (camelCase):
const OBJECTIFIER_UNITLESS = {
boxFlex: true,
boxFlexGroup: true,
columnCount: true,
flex: true,
flexGrow: true,
flexPositive: true,
flexShrink: true,
flexNegative: true,
fontWeight: true,
lineClamp: true,
lineHeight: true,
opacity: true,
order: true,
orphans: true,
tabSize: true,
widows: true,
zIndex: true,
zoom: true,
fillOpacity: true,
strokeDashoffset: true,
strokeOpacity: true,
strokeWidth: true
};userSelect → user-select)user-select → userSelect)--custom-properties are preserved without conversion in both directionscssFloat (JS) ↔ float (CSS) - handles the reserved word conflict:export selectors preserve their original names without camelCase conversion-ms-transform are handled correctly (camelCase: msTransform)px unless property is unitless or value is 0margin: [10, 20])!important is parsed and preservedPostCSS JS handles warnings and errors through:
console.warn with plugin source identificationnull and undefined values are automatically filtered outconst postcssJs = require("postcss-js");
const autoprefixer = require("autoprefixer");
const cssnano = require("cssnano");
// Chain multiple plugins
const processor = postcssJs.sync([
autoprefixer({ browsers: ["last 2 versions"] }),
cssnano({ preset: "default" })
]);const postcss = require("postcss");
const postcssJs = require("postcss-js");
// Use as custom parser
const result = await postcss([/* plugins */])
.process(cssInJsObject, {
parser: postcssJs,
from: undefined
});// Works with any CSS-in-JS library
const styled = require("styled-components");
const postcssJs = require("postcss-js");
const autoprefixer = require("autoprefixer");
const prefixer = postcssJs.sync([autoprefixer]);
const Button = styled.button(prefixer({
display: "flex",
userSelect: "none"
}));