SyntaxStudy
Sign Up
Tailwind CSS Writing a Custom Tailwind Plugin
Tailwind CSS Beginner 1 min read

Writing a Custom Tailwind Plugin

Tailwind plugins are functions that inject additional styles, utilities, components, or variants into the framework using the plugin API. A plugin is registered in tailwind.config.js under the plugins array. The plugin function receives a helpers object exposing addUtilities, addComponents, addBase, addVariant, matchUtilities, matchComponents, theme, and config — giving you full programmatic access to the CSS generation pipeline. The addUtilities helper accepts an object of CSS rules, each key being a class name and each value being an object of CSS properties. The matchUtilities helper is more powerful — it registers a utility that accepts a value from the theme scale, enabling classes like text-shadow-sm or scrollbar-w-2 that behave like built-in Tailwind utilities with full scale support, arbitrary value support via [], and modifier support. Plugins can also add new variants with addVariant. A variant like hocus: that applies styles on both hover and focus — common in accessibility-conscious design systems — can be added with addVariant('hocus', ['&:hover', '&:focus']). The variant then works as a prefix on any utility: hocus:bg-blue-700, hocus:ring-2. This extensibility is what allows the Tailwind ecosystem of plugins to feel like first-party features.
Example
// tailwind.config.js — custom plugin examples
const plugin = require('tailwindcss/plugin');

module.exports = {
  content: ['./src/**/*.{html,js,jsx}'],
  theme: {
    extend: {
      textShadow: {
        sm:  '1px 1px 2px rgba(0,0,0,0.2)',
        DEFAULT: '2px 2px 4px rgba(0,0,0,0.3)',
        lg:  '4px 4px 8px rgba(0,0,0,0.4)',
      },
    },
  },
  plugins: [
    // Plugin 1: text-shadow utilities using matchUtilities
    plugin(function ({ matchUtilities, theme }) {
      matchUtilities(
        {
          'text-shadow': (value) => ({
            textShadow: value,
          }),
        },
        { values: theme('textShadow') }
      );
    }),

    // Plugin 2: custom hocus: variant (hover + focus combined)
    plugin(function ({ addVariant }) {
      addVariant('hocus', ['&:hover', '&:focus']);
      addVariant('group-hocus', ['.group:hover &', '.group:focus &']);
    }),

    // Plugin 3: fluid type utility
    plugin(function ({ addUtilities }) {
      addUtilities({
        '.fluid-h1': {
          fontSize: 'clamp(1.75rem, 4vw + 1rem, 3.5rem)',
          lineHeight: '1.1',
          fontWeight: '800',
        },
        '.fluid-h2': {
          fontSize: 'clamp(1.375rem, 2.5vw + 0.75rem, 2.5rem)',
          lineHeight: '1.2',
          fontWeight: '700',
        },
        '.fluid-body': {
          fontSize: 'clamp(1rem, 0.5vw + 0.875rem, 1.125rem)',
          lineHeight: '1.7',
        },
      });
    }),

    // Official plugins
    require('@tailwindcss/forms'),
    require('@tailwindcss/typography'),
    require('@tailwindcss/aspect-ratio'),
  ],
};