Tailwind Plugins
Build custom Tailwind CSS plugins that add utilities, components, and variants.
You are an expert in the Tailwind CSS plugin API (v3.4+ and v4). You create custom utilities, component classes, and variants that integrate seamlessly with Tailwind's JIT engine, respect the theme configuration, and compose naturally with existing utility classes.
## Key Points
- **Using `addUtilities` when values should be dynamic** -- prefer `matchUtilities` so users can pass arbitrary values with bracket syntax like `text-shadow-[0_2px_4px_red]`.
- **Registering dozens of static component classes** -- this recreates Bootstrap; keep plugins utility-first and compose in markup.
- **Ignoring `important` config** -- always let Tailwind handle specificity; avoid `!important` in plugin CSS.
- **Not declaring `content` paths for plugin-added classes** -- classes generated by `addComponents` still need to appear in scanned files.
- Adding design-system tokens (spacing scales, type scales, color aliases) as first-class Tailwind values.
- Creating project-specific utilities like fluid type, logical properties, or glass effects.
- Wrapping third-party CSS patterns (e.g., skeleton loaders, focus rings) as composable Tailwind classes.
- Building a shareable Tailwind preset for a multi-app monorepo.
- Implementing custom variants for states Tailwind doesn't cover (e.g., `hocus`, `aria-current`).
## Quick Example
```bash
npm install tailwindcss@latest
npm install -D postcss autoprefixer
```
```typescript
// Ignores user theme customization
plugin(function ({ addUtilities }) {
addUtilities({ ".text-shadow-sm": { textShadow: "0 1px 2px rgb(0 0 0 / 0.1)" } });
});
```skilldb get design-tool-services-skills/Tailwind PluginsFull skill: 197 linesTailwind CSS Custom Plugins
You are an expert in the Tailwind CSS plugin API (v3.4+ and v4). You create custom utilities, component classes, and variants that integrate seamlessly with Tailwind's JIT engine, respect the theme configuration, and compose naturally with existing utility classes.
Core Philosophy
Extend, Don't Override
Plugins should add capabilities to Tailwind's existing system. Use theme.extend to add values without clobbering defaults. Register utilities under clear namespaces so they coexist with core utilities.
Theme-Aware by Default
Every magic number in a plugin should reference theme() values. This ensures dark mode, responsive breakpoints, and custom theme overrides propagate automatically.
Composable Primitives
Design plugin utilities as single-purpose building blocks. A .card component class is less flexible than composable .surface, .rounded-card, and .shadow-card utilities.
Setup
npm install tailwindcss@latest
npm install -D postcss autoprefixer
// tailwind.config.ts
import type { Config } from "tailwindcss";
import plugin from "tailwindcss/plugin";
export default {
content: ["./src/**/*.{ts,tsx,html}"],
theme: {
extend: {
colors: {
brand: { 500: "#6366f1", 600: "#4f46e5" },
},
},
},
plugins: [
// inline plugin or require("./plugins/my-plugin")
],
} satisfies Config;
Key Patterns
Do: Use matchUtilities for value-driven utilities
plugin(function ({ matchUtilities, theme }) {
matchUtilities(
{ "text-shadow": (value) => ({ textShadow: value }) },
{ values: theme("textShadow") }
);
});
Not: Hard-code values inside the plugin
// Ignores user theme customization
plugin(function ({ addUtilities }) {
addUtilities({ ".text-shadow-sm": { textShadow: "0 1px 2px rgb(0 0 0 / 0.1)" } });
});
Do: Register custom variants with addVariant
plugin(function ({ addVariant }) {
addVariant("hocus", ["&:hover", "&:focus"]);
addVariant("group-hocus", [":merge(.group):hover &", ":merge(.group):focus &"]);
});
// Usage: <button class="hocus:ring-2">
Common Patterns
Fluid typography utility
plugin(function ({ matchUtilities, theme }) {
matchUtilities(
{
"text-fluid": (value: string) => {
const [min, max] = value.split("_");
return {
fontSize: `clamp(${min}, 2vw + 1rem, ${max})`,
};
},
},
{
values: {
sm: "0.875rem_1.125rem",
base: "1rem_1.25rem",
lg: "1.25rem_1.75rem",
xl: "1.5rem_2.25rem",
},
}
);
});
// Usage: <h1 class="text-fluid-xl">
Component class with theme values
plugin(function ({ addComponents, theme }) {
addComponents({
".btn": {
padding: `${theme("spacing.2")} ${theme("spacing.4")}`,
borderRadius: theme("borderRadius.lg"),
fontWeight: theme("fontWeight.semibold"),
fontSize: theme("fontSize.sm"),
transition: "background-color 150ms ease",
},
".btn-primary": {
backgroundColor: theme("colors.brand.500"),
color: theme("colors.white"),
"&:hover": { backgroundColor: theme("colors.brand.600") },
},
});
});
Logical property utilities
plugin(function ({ matchUtilities, theme }) {
matchUtilities(
{
"mbs": (value) => ({ marginBlockStart: value }),
"mbe": (value) => ({ marginBlockEnd: value }),
"mis": (value) => ({ marginInlineStart: value }),
"mie": (value) => ({ marginInlineEnd: value }),
},
{ values: theme("margin"), supportsNegativeValues: true }
);
});
// Usage: <div class="mbs-4 mie-2">
Shareable plugin with options
// plugins/glass.ts
import plugin from "tailwindcss/plugin";
export const glass = plugin.withOptions<{ blur?: string }>(
(options = {}) =>
function ({ addUtilities }) {
const blur = options.blur ?? "12px";
addUtilities({
".glass": {
background: "rgba(255, 255, 255, 0.1)",
backdropFilter: `blur(${blur})`,
border: "1px solid rgba(255, 255, 255, 0.15)",
},
});
},
() => ({}) // optional theme extensions
);
// tailwind.config.ts
// plugins: [glass({ blur: "16px" })]
Dark mode aware base styles
plugin(function ({ addBase, theme }) {
addBase({
":root": {
"--surface": theme("colors.white"),
"--on-surface": theme("colors.gray.900"),
},
".dark": {
"--surface": theme("colors.gray.900"),
"--on-surface": theme("colors.gray.100"),
},
});
});
Anti-Patterns
- Using
addUtilitieswhen values should be dynamic -- prefermatchUtilitiesso users can pass arbitrary values with bracket syntax liketext-shadow-[0_2px_4px_red]. - Registering dozens of static component classes -- this recreates Bootstrap; keep plugins utility-first and compose in markup.
- Ignoring
importantconfig -- always let Tailwind handle specificity; avoid!importantin plugin CSS. - Not declaring
contentpaths for plugin-added classes -- classes generated byaddComponentsstill need to appear in scanned files.
When to Use
- Adding design-system tokens (spacing scales, type scales, color aliases) as first-class Tailwind values.
- Creating project-specific utilities like fluid type, logical properties, or glass effects.
- Wrapping third-party CSS patterns (e.g., skeleton loaders, focus rings) as composable Tailwind classes.
- Building a shareable Tailwind preset for a multi-app monorepo.
- Implementing custom variants for states Tailwind doesn't cover (e.g.,
hocus,aria-current).
Install this skill directly: skilldb add design-tool-services-skills
Related Skills
Canvas API
Draw graphics and generate images with the HTML Canvas 2D API and node-canvas.
Chromatic
Automate visual regression testing with Chromatic. Configure snapshot capture,
Design Tokens
Manage cross-platform design tokens with Style Dictionary. Define token schemas,
Figma API
Integrate with the Figma REST API and webhooks to read design files, extract components,
Iconify
Integrate icons at scale with the Iconify framework. Use framework-specific
Sharp
Process images at high performance with Sharp. Resize, crop, convert formats,