Next generation utility-first CSS framework with on-demand generation and Tailwind compatibility.
—
WindiCSS features a powerful plugin system that allows you to extend the framework with custom utilities, components, variants, and base styles. The plugin API provides a comprehensive set of utilities for creating flexible and reusable extensions.
Main plugin creation function for developing WindiCSS extensions.
/**
* Creates a WindiCSS plugin
* @param handler - Function that receives plugin utilities and defines the plugin behavior
* @param config - Optional configuration to merge with the processor config
* @returns Plugin object that can be added to the plugins array
*/
function plugin(
handler: (utils: PluginUtils) => void,
config?: Config
): PluginOutput;
interface PluginOutput {
handler: (utils: PluginUtils) => void;
config?: Config;
}Usage Examples:
import plugin from "windicss/plugin";
// Basic plugin
const buttonPlugin = plugin(({ addComponents }) => {
addComponents({
'.btn': {
padding: '0.5rem 1rem',
borderRadius: '0.375rem',
fontWeight: '500',
transition: 'all 0.2s'
},
'.btn-primary': {
backgroundColor: '#3b82f6',
color: '#ffffff'
}
});
});
// Plugin with configuration
const customPlugin = plugin(({ addUtilities, theme }) => {
addUtilities({
'.gradient-text': {
background: `linear-gradient(45deg, ${theme('colors.blue.500')}, ${theme('colors.purple.500')})`,
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent'
}
});
}, {
theme: {
extend: {
colors: {
brand: '#ff6b6b'
}
}
}
});Creates configurable plugins that accept options for customization.
/**
* Creates a plugin that accepts options for customization
* @param pluginFunction - Function that takes options and returns a plugin handler
* @param configFunction - Optional function that takes options and returns config
* @returns Function that accepts options and returns a plugin
*/
plugin.withOptions<T>(
pluginFunction: (options: T) => (utils: PluginUtils) => void,
configFunction?: (options: T) => Config
): PluginWithOptions<T>;
interface PluginWithOptions<T> {
(options?: T): PluginOutput;
__isOptionsFunction: true;
}Usage Examples:
// Plugin with options
const flexboxPlugin = plugin.withOptions<{
gap?: boolean;
grid?: boolean;
}>((options = {}) => ({ addUtilities }) => {
const utilities: Record<string, any> = {
'.flex-center': {
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}
};
if (options.gap) {
utilities['.flex-gap'] = {
display: 'flex',
gap: '1rem'
};
}
if (options.grid) {
utilities['.grid-center'] = {
display: 'grid',
placeItems: 'center'
};
}
addUtilities(utilities);
});
// Usage with options
const processor = new Processor({
plugins: [
flexboxPlugin({ gap: true, grid: true })
]
});Complete interface provided to plugin handlers for adding utilities, components, and more.
interface PluginUtils {
/** Add utility classes */
addUtilities(utilities: Record<string, any>, options?: PluginUtilOptions): Style[];
/** Add component classes */
addComponents(components: Record<string, any>, options?: PluginUtilOptions): Style[];
/** Add base/global styles */
addBase(baseStyles: Record<string, any>): Style[];
/** Add custom variant */
addVariant(name: string, generator: VariantGenerator): Style | Style[];
/** Add dynamic utility generator */
addDynamic(key: string, generator: UtilityGenerator, options?: PluginUtilOptions): UtilityGenerator;
/** Access theme values */
theme(path: string, defaultValue?: any): any;
/** Access config values */
config(path: string, defaultValue?: any): any;
/** Escape CSS selector */
e(selector: string): string;
/** Add prefix to selector */
prefix(selector: string): string;
/** Access variant utilities */
variants(path: string, defaultValue?: string[]): string[];
}
interface PluginUtilOptions {
/** Whether to respect the configured prefix */
respectPrefix?: boolean;
/** Whether to respect the important configuration */
respectImportant?: boolean;
/** Whether to respect existing selector */
respectSelector?: boolean;
/** CSS layer for the utilities */
layer?: "base" | "components" | "utilities";
/** Variants to apply to utilities */
variants?: string[];
/** Order for CSS generation */
order?: number;
/** Group name for organization */
group?: string;
/** Completions for IDE support */
completions?: string[];
}Add custom utility classes to WindiCSS.
/**
* Adds custom utility classes
* @param utilities - Object with CSS selectors as keys and style objects as values
* @param options - Options for utility generation
* @returns Array of generated Style objects
*/
addUtilities(
utilities: Record<string, any> | Array<Record<string, any>>,
options?: PluginUtilOptions
): Style[];Usage Examples:
const utilitiesPlugin = plugin(({ addUtilities }) => {
// Basic utilities
addUtilities({
'.scroll-smooth': {
scrollBehavior: 'smooth'
},
'.scroll-auto': {
scrollBehavior: 'auto'
}
});
// Utilities with variants and layer
addUtilities({
'.backdrop-blur': {
backdropFilter: 'blur(8px)'
},
'.backdrop-blur-sm': {
backdropFilter: 'blur(4px)'
}
}, {
respectPrefix: true,
respectImportant: true,
layer: 'utilities',
variants: ['responsive', 'hover']
});
// Responsive utilities
addUtilities({
'.container-xs': {
maxWidth: '480px',
marginLeft: 'auto',
marginRight: 'auto'
},
'.container-sm': {
maxWidth: '640px',
marginLeft: 'auto',
marginRight: 'auto'
}
});
});Add custom component classes with higher specificity than utilities.
/**
* Adds custom component classes
* @param components - Object with CSS selectors as keys and style objects as values
* @param options - Options for component generation
* @returns Array of generated Style objects
*/
addComponents(
components: Record<string, any> | Array<Record<string, any>>,
options?: PluginUtilOptions
): Style[];Usage Examples:
const componentsPlugin = plugin(({ addComponents, theme }) => {
addComponents({
// Button components
'.btn': {
padding: '0.5rem 1rem',
borderRadius: theme('borderRadius.md'),
fontWeight: theme('fontWeight.medium'),
transition: 'all 0.15s ease-in-out',
cursor: 'pointer',
border: 'none',
'&:focus': {
outline: 'none',
boxShadow: '0 0 0 3px rgba(59, 130, 246, 0.1)'
}
},
'.btn-sm': {
padding: '0.25rem 0.75rem',
fontSize: theme('fontSize.sm')
},
'.btn-lg': {
padding: '0.75rem 1.5rem',
fontSize: theme('fontSize.lg')
},
// Card component
'.card': {
backgroundColor: theme('colors.white'),
borderRadius: theme('borderRadius.lg'),
boxShadow: theme('boxShadow.md'),
padding: theme('spacing.6')
}
});
});Add global base styles that apply to HTML elements.
/**
* Adds base/global styles
* @param baseStyles - Object with selectors and style objects
* @returns Array of generated Style objects
*/
addBase(baseStyles: Record<string, any>): Style[];Usage Examples:
const basePlugin = plugin(({ addBase, theme }) => {
addBase({
// Global styles
'html': {
scrollBehavior: 'smooth'
},
'body': {
fontFamily: theme('fontFamily.sans'),
lineHeight: theme('lineHeight.normal'),
color: theme('colors.gray.900'),
backgroundColor: theme('colors.gray.50')
},
// Custom elements
'h1, h2, h3, h4, h5, h6': {
fontWeight: theme('fontWeight.semibold'),
marginBottom: theme('spacing.4')
},
'p': {
marginBottom: theme('spacing.4')
},
// CSS custom properties
':root': {
'--primary-color': theme('colors.blue.500'),
'--secondary-color': theme('colors.green.500')
}
});
});Add dynamic utility generators that create utilities based on arbitrary values.
/**
* Adds dynamic utility generator
* @param key - Pattern to match for generating utilities
* @param generator - Function that generates styles based on matched values
* @param options - Options for utility generation
* @returns The generator function
*/
addDynamic(
key: string,
generator: UtilityGenerator,
options?: PluginUtilOptions
): UtilityGenerator;
type UtilityGenerator = (props: {
Utility: any;
Style: any;
Property: any;
Keyframes: any;
}) => Style | Style[] | undefined;Usage Examples:
const dynamicPlugin = plugin(({ addDynamic }) => {
// Custom spacing utilities
addDynamic('p-custom', ({ Utility, Style, Property }) => {
const match = Utility.raw.match(/^p-custom-(.+)$/);
if (match) {
const value = match[1];
return new Style(Utility.class, [
new Property('padding', `${value}px`)
]);
}
});
// Custom color utilities with opacity
addDynamic('bg-custom', ({ Utility, Style, Property }) => {
const match = Utility.raw.match(/^bg-custom-([a-zA-Z]+)-(\d+)$/);
if (match) {
const [, color, opacity] = match;
const opacityValue = parseInt(opacity) / 100;
return new Style(Utility.class, [
new Property('background-color', `rgba(var(--color-${color}), ${opacityValue})`)
]);
}
});
});Add custom variants for conditional styling.
/**
* Adds custom variant
* @param name - Name of the variant
* @param generator - Function that generates the variant style wrapper
* @returns Generated variant style
*/
addVariant(name: string, generator: VariantGenerator): Style | Style[];
type VariantGenerator = (utils: VariantUtils) => Style;
interface VariantUtils {
modifySelectors(modifier: (args: { className: string }) => string): Style;
atRule(name: string): Style;
pseudoClass(name: string): Style;
pseudoElement(name: string): Style;
parent(name: string): Style;
child(name: string): Style;
separator: string;
style: Style;
}Usage Examples:
const variantsPlugin = plugin(({ addVariant }) => {
// Custom pseudo-class variant
addVariant('hocus', ({ pseudoClass }) => {
return pseudoClass('hover, &:focus');
});
// Custom media query variant
addVariant('supports-grid', ({ atRule }) => {
return atRule('@supports (display: grid)');
});
// Custom parent selector variant
addVariant('group-hover', ({ modifySelectors }) => {
return modifySelectors(({ className }) => {
return `.group:hover .${className}`;
});
});
// Custom sibling variant
addVariant('sibling-checked', ({ modifySelectors }) => {
return modifySelectors(({ className }) => {
return `input[type="checkbox"]:checked ~ .${className}`;
});
});
});Access theme values and configuration within plugins.
/**
* Access theme values by path
* @param path - Dot-separated path to theme value
* @param defaultValue - Default value if path doesn't exist
* @returns Theme value or default
*/
theme(path: string, defaultValue?: any): any;
/**
* Access configuration values by path
* @param path - Dot-separated path to config value
* @param defaultValue - Default value if path doesn't exist
* @returns Config value or default
*/
config(path: string, defaultValue?: any): any;Usage Examples:
const themePlugin = plugin(({ addUtilities, theme, config }) => {
// Access theme values
const primaryColor = theme('colors.blue.500');
const borderRadius = theme('borderRadius.lg');
const fontFamily = theme('fontFamily.sans');
// Access config values
const prefix = config('prefix', '');
const separator = config('separator', ':');
const important = config('important', false);
addUtilities({
'.brand-card': {
backgroundColor: primaryColor,
borderRadius: borderRadius,
fontFamily: fontFamily.join(', '),
color: theme('colors.white'),
padding: theme('spacing.6')
}
});
});WindiCSS includes several built-in plugins that demonstrate the plugin system capabilities.
import aspectRatio from "windicss/plugin/aspect-ratio";
import filters from "windicss/plugin/filters";
import forms from "windicss/plugin/forms";
import lineClamp from "windicss/plugin/line-clamp";
import typography from "windicss/plugin/typography";
import scrollSnap from "windicss/plugin/scroll-snap";Usage Example:
import Processor from "windicss";
import typography from "windicss/plugin/typography";
import forms from "windicss/plugin/forms";
const processor = new Processor({
plugins: [
typography({
modifiers: ['sm', 'lg', 'xl'],
className: 'prose'
}),
forms
]
});Install with Tessl CLI
npx tessl i tessl/npm-windicss