Presets 
Presets allow you to create reusable, shareable configurations that can be used across multiple Headwind projects. They're perfect for maintaining design systems, organizational standards, or common UI patterns.
Overview 
A preset is a configuration object that can include theme customization, shortcuts, custom rules, variants, and preflight CSS. Instead of duplicating configurations across projects, you can package them as presets and import them where needed.
// Before: Duplicate configuration in each project
// project-a/headwind.config.ts
// After: Share configuration via preset
import { companyPreset } from '@company/headwind-preset'
const config = {
  theme: { colors: { primary: '#3b82f6' } },
  shortcuts: { btn: 'px-4 py-2 rounded' },
}
// project-b/headwind.config.ts
const config = {
  theme: { colors: { primary: '#3b82f6' } },
  shortcuts: { btn: 'px-4 py-2 rounded' },
}
const config = {
  presets: [companyPreset],
}Creating a Preset 
Basic Preset Structure 
A preset is an object that implements the Preset interface:
import type { Preset } from 'headwind'
export const myPreset: Preset = {
  name: 'my-preset',
  theme: {
    // Theme customization
  },
  shortcuts: {
    // Shortcuts
  },
  rules: [
    // Custom rules
  ],
  variants: {
    // Variant configuration
  },
  preflights: [
    // Preflight CSS
  ],
}Simple Example 
// presets/minimal.ts
import type { Preset } from 'headwind'
export const minimalPreset: Preset = {
  name: 'minimal',
  theme: {
    colors: {
      primary: '#000000',
      secondary: '#ffffff',
    },
    spacing: {
      0: '0',
      1: '0.25rem',
      2: '0.5rem',
      4: '1rem',
      8: '2rem',
    },
  },
  shortcuts: {
    'btn': 'px-4 py-2 border-2 border-black transition-colors',
    'btn-filled': 'btn bg-black text-white hover:bg-gray-800',
    'btn-outline': 'btn bg-white text-black hover:bg-gray-100',
  },
}Using Presets 
Single Preset 
// headwind.config.ts
import type { HeadwindOptions } from 'headwind'
import { minimalPreset } from './presets/minimal'
const config = {
  content: ['./src/**/*.{html,js,ts,jsx,tsx}'],
  output: './dist/headwind.css',
  presets: [minimalPreset],
} satisfies HeadwindOptions
export default configMultiple Presets 
Presets are merged in order, with later presets taking precedence:
import { basePreset } from './presets/base'
import { componentsPreset } from './presets/components'
import { utilitiesPreset } from './presets/utilities'
const config = {
  presets: [
    basePreset, // Applied first
    componentsPreset, // Applied second, overrides base
    utilitiesPreset, // Applied last, overrides both
  ],
}Extending Presets 
You can extend a preset with additional configuration:
import { companyPreset } from '@company/headwind-preset'
const config = {
  presets: [companyPreset],
  // Add or override theme values
  theme: {
    colors: {
      accent: '#ff5500', // Add new color
    },
  },
  // Add custom shortcuts
  shortcuts: {
    'project-specific': 'custom utilities',
  },
}Preset Examples 
Design System Preset 
// presets/design-system.ts
import type { Preset } from 'headwind'
export const designSystemPreset: Preset = {
  name: 'design-system',
  theme: {
    colors: {
      brand: {
        50: '#eff6ff',
        100: '#dbeafe',
        200: '#bfdbfe',
        300: '#93c5fd',
        400: '#60a5fa',
        500: '#3b82f6',
        600: '#2563eb',
        700: '#1d4ed8',
        800: '#1e40af',
        900: '#1e3a8a',
      },
      success: '#10b981',
      warning: '#f59e0b',
      danger: '#ef4444',
      info: '#3b82f6',
    },
    fontFamily: {
      sans: ['Inter', 'system-ui', 'sans-serif'],
      mono: ['Fira Code', 'monospace'],
    },
    fontSize: {
      'xs': ['0.75rem', { lineHeight: '1rem' }],
      'sm': ['0.875rem', { lineHeight: '1.25rem' }],
      'base': ['1rem', { lineHeight: '1.5rem' }],
      'lg': ['1.125rem', { lineHeight: '1.75rem' }],
      'xl': ['1.25rem', { lineHeight: '1.75rem' }],
      '2xl': ['1.5rem', { lineHeight: '2rem' }],
      '3xl': ['1.875rem', { lineHeight: '2.25rem' }],
      '4xl': ['2.25rem', { lineHeight: '2.5rem' }],
    },
    spacing: {
      0: '0',
      1: '0.25rem',
      2: '0.5rem',
      3: '0.75rem',
      4: '1rem',
      5: '1.25rem',
      6: '1.5rem',
      8: '2rem',
      10: '2.5rem',
      12: '3rem',
      16: '4rem',
      20: '5rem',
    },
  },
  shortcuts: {
    // Buttons
    'btn': 'inline-flex items-center justify-center font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2',
    'btn-primary': 'btn bg-brand-500 text-white hover:bg-brand-600 focus:ring-brand-500',
    'btn-secondary': 'btn bg-gray-200 text-gray-900 hover:bg-gray-300 focus:ring-gray-500',
    'btn-success': 'btn bg-success text-white hover:opacity-90 focus:ring-success',
    'btn-danger': 'btn bg-danger text-white hover:opacity-90 focus:ring-danger',
    // Cards
    'card': 'bg-white rounded-lg shadow',
    'card-header': 'px-6 py-4 border-b border-gray-200',
    'card-body': 'px-6 py-4',
    'card-footer': 'px-6 py-4 bg-gray-50 border-t border-gray-200',
    // Forms
    'input': 'block w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-brand-500 focus:border-brand-500',
    'label': 'block text-sm font-medium text-gray-700 mb-1',
  },
}Component Library Preset 
// presets/components.ts
import type { Preset } from 'headwind'
export const componentsPreset: Preset = {
  name: 'components',
  shortcuts: {
    // Navigation
    'nav': 'flex items-center justify-between px-6 py-4 bg-white shadow',
    'nav-link': 'px-3 py-2 text-gray-700 hover:text-gray-900 transition-colors',
    'nav-link-active': 'nav-link text-blue-500 font-semibold',
    // Badges
    'badge': 'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium',
    'badge-primary': 'badge bg-blue-100 text-blue-800',
    'badge-success': 'badge bg-green-100 text-green-800',
    'badge-warning': 'badge bg-yellow-100 text-yellow-800',
    'badge-danger': 'badge bg-red-100 text-red-800',
    // Alerts
    'alert': 'p-4 rounded-md',
    'alert-info': 'alert bg-blue-50 text-blue-800 border border-blue-200',
    'alert-success': 'alert bg-green-50 text-green-800 border border-green-200',
    'alert-warning': 'alert bg-yellow-50 text-yellow-800 border border-yellow-200',
    'alert-danger': 'alert bg-red-50 text-red-800 border border-red-200',
    // Modals
    'modal-overlay': 'fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4',
    'modal': 'bg-white rounded-lg shadow-xl max-w-md w-full',
    'modal-header': 'px-6 py-4 border-b border-gray-200',
    'modal-body': 'px-6 py-4',
    'modal-footer': 'px-6 py-4 bg-gray-50 border-t border-gray-200 flex justify-end gap-2',
    // Tables
    'table': 'min-w-full divide-y divide-gray-200',
    'table-header': 'bg-gray-50',
    'table-row': 'hover:bg-gray-50 transition-colors',
    'table-cell': 'px-6 py-4 whitespace-nowrap text-sm',
  },
}Utility Preset 
// presets/utilities.ts
import type { Preset } from 'headwind'
export const utilitiesPreset: Preset = {
  name: 'utilities',
  shortcuts: {
    // Layout helpers
    'flex-center': 'flex items-center justify-center',
    'flex-between': 'flex items-center justify-between',
    'flex-col-center': 'flex flex-col items-center justify-center',
    // Container
    'container': 'max-w-7xl mx-auto px-4 sm:px-6 lg:px-8',
    'container-sm': 'max-w-4xl mx-auto px-4',
    'container-xs': 'max-w-2xl mx-auto px-4',
    // Typography
    'text-link': 'text-blue-500 hover:text-blue-600 underline',
    'text-muted': 'text-gray-600',
    'text-emphasis': 'text-gray-900 font-semibold',
    // Truncate
    'truncate-1': 'overflow-hidden text-ellipsis line-clamp-1',
    'truncate-2': 'overflow-hidden text-ellipsis line-clamp-2',
    'truncate-3': 'overflow-hidden text-ellipsis line-clamp-3',
  },
  rules: [
    // Custom gradient rule
    [
      /^bg-gradient-(\w+)$/,
      (match) => {
        const direction = match[1]
        const directions: Record<string, string> = {
          t: 'to top',
          r: 'to right',
          b: 'to bottom',
          l: 'to left',
          tr: 'to top right',
          br: 'to bottom right',
          bl: 'to bottom left',
          tl: 'to top left',
        }
        return {
          'background-image': `linear-gradient(${directions[direction] || 'to right'}, var(--tw-gradient-stops))`,
        }
      },
    ],
  ],
}Framework-Specific Preset 
// presets/react.ts
import type { Preset } from 'headwind'
export const reactPreset: Preset = {
  name: 'react',
  shortcuts: {
    // React-specific component patterns
    'react-button': 'px-4 py-2 rounded font-semibold transition-colors disabled:opacity-50 disabled:cursor-not-allowed',
    'react-input': 'block w-full px-3 py-2 border rounded-md focus:outline-none disabled:bg-gray-100',
    'react-select': 'block w-full px-3 py-2 border rounded-md focus:outline-none appearance-none',
    // Loading states
    'loading': 'animate-pulse',
    'loading-spinner': 'animate-spin',
    // Focus visible (keyboard navigation)
    'focus-ring': 'focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2',
  },
  variants: {
    // Enable all variants for React components
    'hover': true,
    'focus': true,
    'active': true,
    'disabled': true,
    'focus-visible': true,
    'focus-within': true,
  },
}Publishing Presets 
As NPM Package 
Create a shareable preset package:
# Create package
mkdir my-headwind-preset
cd my-headwind-preset
bun init
# Package structure
my-headwind-preset/
├── package.json
├── src/
│   └── index.ts
└── tsconfig.json// src/index.ts
import type { Preset } from 'headwind'
export const myPreset: Preset = {
  name: 'my-preset',
  // ... configuration
}
export default myPreset// package.json
{
  "name": "@company/headwind-preset",
  "version": "1.0.0",
  "type": "module",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "types": "./dist/index.d.ts"
    }
  },
  "scripts": {
    "build": "tsc",
    "prepublishOnly": "bun run build"
  },
  "peerDependencies": {
    "headwind": ">=1.0.0"
  },
  "devDependencies": {
    "headwind": "latest",
    "typescript": "latest"
  }
}Usage of Published Preset 
bun add @company/headwind-preset// headwind.config.ts
import { myPreset } from '@company/headwind-preset'
const config = {
  presets: [myPreset],
}Preset Composition 
Layered Presets 
Build complex configurations by layering presets:
// Base layer - foundational styles
const basePreset: Preset = {
  name: 'base',
  theme: {
    colors: { /* base colors */ },
  },
}
// Component layer - reusable components
const componentPreset: Preset = {
  name: 'components',
  shortcuts: { /* component shortcuts */ },
}
// Brand layer - company branding
const brandPreset: Preset = {
  name: 'brand',
  theme: {
    colors: { brand: '#3b82f6' },
  },
}
// Combine in config
const config = {
  presets: [basePreset, componentPreset, brandPreset],
}Conditional Presets 
Apply presets based on environment:
const isDev = process.env.NODE_ENV === 'development'
const config = {
  presets: [
    basePreset,
    componentPreset,
    ...(isDev ? [devPreset] : [prodPreset]),
  ],
}Advanced Preset Patterns 
Preset with Custom Preflight 
import type { Preflight, Preset } from 'headwind'
const customPreflight: Preflight = {
  getCSS: () => `
    /* Custom reset */
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    html {
      font-family: 'Inter', sans-serif;
    }
    body {
      line-height: 1.6;
      color: #333;
    }
  `,
}
export const presetWithPreflight: Preset = {
  name: 'with-preflight',
  preflights: [customPreflight],
}Preset Factory 
Create presets dynamically:
interface BrandConfig {
  primary: string
  secondary: string
  accent: string
}
export function createBrandPreset(brand: BrandConfig): Preset {
  return {
    name: `brand-${brand.primary}`,
    theme: {
      colors: {
        primary: brand.primary,
        secondary: brand.secondary,
        accent: brand.accent,
      },
    },
    shortcuts: {
      'btn-primary': `btn bg-[${brand.primary}] text-white`,
      'btn-secondary': `btn bg-[${brand.secondary}] text-white`,
      'link': `text-[${brand.accent}] hover:underline`,
    },
  }
}
// Usage
const myBrandPreset = createBrandPreset({
  primary: '#3b82f6',
  secondary: '#8b5cf6',
  accent: '#10b981',
})
const config = {
  presets: [myBrandPreset],
}Best Practices 
1. Name Your Presets 
Always provide a descriptive name:
const preset: Preset = {
  name: 'company-design-system', // ✅ Clear and descriptive
  // ...
}2. Document Your Presets 
Include documentation in your preset files:
/**
 * Company Design System Preset
 *
 * Includes:
 * - Brand colors and typography
 * - Standard component shortcuts
 * - Form utilities
 *
 * @example
 * import { companyPreset } from '@company/headwind-preset'
 *
 * const config = {
 *   presets: [companyPreset],
 * }
 */
export const companyPreset: Preset = {
  // ...
}3. Version Your Presets 
Use semantic versioning for published presets:
- Major: Breaking changes to shortcuts or theme
- Minor: New shortcuts or theme additions
- Patch: Bug fixes or improvements
4. Keep Presets Focused 
Create multiple focused presets rather than one monolithic preset:
import { componentPreset } from './presets/components'
// ❌ Avoid - everything in one preset
import { everythingPreset } from './presets/everything'
// ✅ Good - focused presets
import { themePreset } from './presets/theme'
import { utilityPreset } from './presets/utilities'5. Provide Examples 
Include usage examples with your preset:
// presets/example.ts
export const examplePreset: Preset = {
  name: 'example',
  shortcuts: {
    btn: 'px-4 py-2 rounded',
  },
}
// Example usage
const exampleConfig = {
  presets: [examplePreset],
}
// <button class="btn">Click Me</button>Troubleshooting 
Preset Not Applied 
Check:
- Preset is imported correctly: typescript- import { myPreset } from './presets/my-preset'
- Preset is added to config: typescript- const config = { presets: [myPreset], // ✅ }
- Preset has correct structure: typescript- const preset: Preset = { name: 'my-preset', // Required // ... }
Preset Order Issues 
Problem: Later presets override earlier ones
Solution: Order presets from most general to most specific:
const config = {
  presets: [
    generalPreset, // Base configuration
    specificPreset, // More specific overrides
  ],
}Type Errors 
Problem: TypeScript errors when creating preset
Solution: Import and use the Preset type:
import type { Preset } from 'headwind'
export const myPreset: Preset = {
  name: 'my-preset',
  // TypeScript will validate structure
}Related 
- Configuration - Main configuration options
- Theme Customization - Customizing themes
- Shortcuts - Creating shortcuts
- Custom Rules - Adding custom rules