CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-windicss

Next generation utility-first CSS framework with on-demand generation and Tailwind compatibility.

Pending
Overview
Eval results
Files

plugin-system.mddocs/

Plugin System

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.

Capabilities

Plugin Creation

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'
      }
    }
  }
});

Plugin with Options

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 })
  ]
});

Plugin Utilities Interface

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[];
}

Adding Utilities

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'
    }
  });
});

Adding Components

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')
    }
  });
});

Adding Base Styles

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')
    }
  });
});

Adding Dynamic Utilities

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})`)
      ]);
    }
  });
});

Adding Variants

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}`;
    });
  });
});

Accessing Theme and Config

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')
    }
  });
});

Built-in Plugin Examples

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

docs

built-in-plugins.md

configuration.md

core-processing.md

helpers.md

index.md

parser-system.md

plugin-system.md

style-system.md

utilities.md

tile.json