PostCSS plugin for Tailwind CSS v4 that provides automated class candidate scanning, CSS compilation, and optimization with intelligent caching and dependency tracking.
npx @tessl/cli install tessl/npm-tailwindcss--postcss@4.1.0@tailwindcss/postcss is a PostCSS plugin that integrates Tailwind CSS v4 into PostCSS-based build pipelines. It provides automated class candidate scanning, CSS compilation, optimization, and intelligent caching with dependency tracking for high-performance builds.
npm install @tailwindcss/postcssimport tailwindcss from "@tailwindcss/postcss";
import { cssAstToPostCssAst, postCssAstToCssAst } from "@tailwindcss/postcss/ast";For CommonJS:
const tailwindcss = require("@tailwindcss/postcss");
const { cssAstToPostCssAst, postCssAstToCssAst } = require("@tailwindcss/postcss/ast");
// Note: The package uses `export =` syntax for CommonJS compatibility
// This ensures proper integration with postcss-load-configimport postcss from "postcss";
import tailwindcss from "@tailwindcss/postcss";
// Basic configuration
const processor = postcss([
tailwindcss({
base: "./src",
optimize: true,
})
]);
// Process CSS with Tailwind
const result = await processor.process(`
@import 'tailwindcss';
.custom-button {
@apply bg-blue-500 text-white px-4 py-2 rounded;
}
`, { from: "input.css" });
console.log(result.css);@tailwindcss/postcss implements a sophisticated two-stage PostCSS processing pipeline:
Key architectural components:
Creates the main PostCSS plugin with configurable options for Tailwind CSS processing.
/**
* Creates a PostCSS plugin for Tailwind CSS v4 processing
* @param opts - Configuration options for the plugin
* @returns PostCSS plugin with Tailwind CSS processing capabilities
*/
function tailwindcss(opts?: PluginOptions): AcceptedPlugin;
/**
* Default export is the tailwindcss function with postcss property
* The plugin function includes a postcss property set to true for PostCSS compatibility
*/
declare const _default: typeof tailwindcss & { postcss: true };
export default _default;
interface PluginOptions {
/**
* The base directory to scan for class candidates.
* Defaults to the current working directory.
*/
base?: string;
/**
* Optimize and minify the output CSS.
* Can be boolean or object with minify option.
* Defaults to true in production (NODE_ENV === 'production').
*/
optimize?: boolean | { minify?: boolean };
/**
* Enable or disable asset URL rewriting.
* Defaults to true.
*/
transformAssetUrls?: boolean;
}
/**
* PostCSS AcceptedPlugin interface
*/
interface AcceptedPlugin {
postcssPlugin: string;
plugins: Plugin[];
}
/**
* PostCSS Plugin interface
*/
interface Plugin {
postcssPlugin: string;
Once?: (root: Root, helpers: { result: Result }) => void | Promise<void>;
OnceExit?: (root: Root, helpers: { result: Result }) => void | Promise<void>;
[key: string]: any;
}Functions for converting between PostCSS and Tailwind CSS AST formats, useful for advanced integrations and plugin development.
/**
* Converts Tailwind CSS AST nodes to PostCSS AST format
* @param ast - Array of Tailwind CSS AST nodes
* @param source - PostCSS source object for source mapping
* @returns PostCSS Root node containing the converted AST
*/
function cssAstToPostCssAst(ast: AstNode[], source: PostcssSource | undefined): Root;
/**
* Converts PostCSS AST to Tailwind CSS AST format
* @param root - PostCSS Root node to convert
* @returns Array of Tailwind CSS AST nodes
*/
function postCssAstToCssAst(root: Root): AstNode[];
/**
* Tailwind CSS AST node types
*/
type AstNode = Declaration | Rule | AtRule | Comment;
interface Declaration {
kind: 'declaration';
property: string;
value: string;
important: boolean;
src?: SourceLocation;
}
interface Rule {
kind: 'rule';
selector: string;
nodes: AstNode[];
src?: SourceLocation;
}
interface AtRule {
kind: 'at-rule';
name: string;
params: string;
nodes: AstNode[];
src?: SourceLocation;
}
interface Comment {
kind: 'comment';
value: string;
src?: SourceLocation;
}
type SourceLocation = [Source, number, number];
interface Source {
file: string | null;
code: string;
}
/**
* PostCSS source interface
*/
interface PostcssSource {
input: Input;
start: Position;
end: Position;
}
interface Position {
line: number;
column: number;
offset: number;
}
interface Input {
css: string;
file?: string;
id?: string;
map?: any;
}
/**
* PostCSS Root and related interfaces
*/
interface Root {
type: 'root';
nodes: ChildNode[];
source?: PostcssSource;
removeAll(): void;
append(node: ChildNode | ChildNode[]): void;
clone(): Root;
each(callback: (node: ChildNode) => void): void;
}
type ChildNode = Rule | AtRule | Declaration | Comment;import postcss from "postcss";
import tailwindcss from "@tailwindcss/postcss";
const processor = postcss([
tailwindcss({
base: "./src",
optimize: false, // Disable optimization for faster builds
transformAssetUrls: true,
})
]);import postcss from "postcss";
import tailwindcss from "@tailwindcss/postcss";
const processor = postcss([
tailwindcss({
base: "./src",
optimize: { minify: true }, // Enable full optimization
transformAssetUrls: true,
})
]);// postcss.config.js
module.exports = {
plugins: [
require("@tailwindcss/postcss")({
base: process.cwd(),
optimize: process.env.NODE_ENV === "production",
}),
],
};// vite.config.ts
import { defineConfig } from "vite";
export default defineConfig({
css: {
postcss: {
plugins: [
require("@tailwindcss/postcss")({
base: "./src",
}),
],
},
},
});// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
"style-loader",
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
require("@tailwindcss/postcss")({
base: "./src",
}),
],
},
},
},
],
},
],
},
};import { cssAstToPostCssAst, postCssAstToCssAst } from "@tailwindcss/postcss/ast";
import postcss from "postcss";
// Convert PostCSS AST to Tailwind CSS AST
const postcssRoot = postcss.parse(`
.test {
color: red;
}
`);
const tailwindAst = postCssAstToCssAst(postcssRoot);
console.log('Tailwind AST:', tailwindAst);
// Convert back to PostCSS AST
const convertedRoot = cssAstToPostCssAst(tailwindAst, postcssRoot.source);
console.log('Converted PostCSS AST:', convertedRoot.toString());The plugin implements graceful error handling:
// Example error handling in usage
try {
const result = await processor.process(css, { from: "input.css" });
console.log(result.css);
} catch (error) {
// Plugin logs errors internally and returns empty CSS
// PostCSS processing continues without crashing
console.log("Processing completed with fallback");
}// next.config.js
module.exports = {
experimental: {
// Next.js automatically configures PostCSS
// Place postcss.config.js in project root
},
};// package.json
{
"browserslist": ["> 1%", "last 2 versions"],
"@parcel/transformer-css": {
"drafts": {
"customMedia": true
}
}
}// rollup.config.js
import postcss from "rollup-plugin-postcss";
export default {
plugins: [
postcss({
plugins: [
require("@tailwindcss/postcss")({
base: "./src",
}),
],
}),
],
};