A lightweight CSS preprocessor that provides CSS parsing, AST manipulation, vendor prefixing, and serialization capabilities.
—
Convert AST nodes back into CSS strings with customizable formatting and processing through callback-based serialization system.
Core serialization function that traverses AST nodes and applies callback functions to generate CSS output.
/**
* Convert AST nodes to CSS string using callback function
* @param children - Array of AST node objects to serialize
* @param callback - Function to process each node and generate CSS
* @returns Serialized CSS string
*/
function serialize(children: object[], callback: function): string;Usage Examples:
import { compile, serialize, stringify } from 'stylis';
// Basic serialization with default stringify
const ast = compile('h1 { color: red; }');
const css = serialize(ast, stringify);
console.log(css); // "h1{color:red;}"
// Custom serialization callback
const customCss = serialize(ast, (element, index, children, callback) => {
if (element.type === 'rule') {
return `/* Rule: ${element.props.join(', ')} */\n${stringify(element, index, children, callback)}`;
}
return stringify(element, index, children, callback);
});
// Serialization with middleware
import { middleware, prefixer } from 'stylis';
const processed = serialize(
compile('div { display: flex; }'),
middleware([prefixer, stringify])
);Default stringification middleware that converts AST nodes into standard CSS syntax.
/**
* Default stringification middleware for AST nodes
* @param element - AST node to stringify
* @param index - Index of node in children array
* @param children - Array of sibling nodes
* @param callback - Recursive callback for child nodes
* @returns CSS string for the element
*/
function stringify(element: object, index: number, children: object[], callback: function): string;Behavior by Node Type:
element.return or element.value@keyframes name { ...children... }selector { ...children... } if selector is non-emptyCustom serialization callbacks follow this interface:
/**
* Serialization callback function interface
* @param element - Current AST node being processed
* @param index - Index of element in parent's children array
* @param children - Array of sibling elements
* @param callback - Recursive callback to process child elements
* @returns CSS string output for this element
*/
interface SerializationCallback {
(element: object, index: number, children: object[], callback: function): string;
}import { compile, serialize } from 'stylis';
const customProcessor = (element, index, children, callback) => {
switch (element.type) {
case 'rule':
// Add custom attributes to selectors
const selectors = element.props.map(selector => `${selector}[data-styled]`);
return `${selectors.join(',')}{${serialize(element.children, callback)}}`;
case 'decl':
// Add !important to all declarations
return `${element.props}:${element.children} !important;`;
default:
return serialize([element], callback);
}
};
const styled = serialize(compile('.component { color: red; }'), customProcessor);const minifier = (element, index, children, callback) => {
if (element.type === 'comm') {
return ''; // Strip comments
}
// Use default processing but remove extra whitespace
const result = stringify(element, index, children, callback);
return result.replace(/\s+/g, ' ').trim();
};
const minified = serialize(compile(`
.component {
padding: 20px;
margin: 10px;
}
`), minifier);const debugSerializer = (element, index, children, callback) => {
const indent = ' '.repeat(getDepth(element));
const nodeInfo = `${indent}/* ${element.type}: ${element.value} */\n`;
const nodeOutput = stringify(element, index, children, callback);
return nodeInfo + nodeOutput;
};
function getDepth(element) {
let depth = 0;
let current = element.parent;
while (current) {
depth++;
current = current.parent;
}
return depth;
}The serialization system provides full control over CSS output formatting:
property: value;property : value ; (with extra spacing)The serialization system is designed to handle malformed AST gracefully:
Serialization errors are typically non-fatal and result in partial CSS output rather than throwing exceptions.
Install with Tessl CLI
npx tessl i tessl/npm-stylis