Custom Utilities and Plugins
Create your own variant-aware utilities with @utility, and know when a plugin fits.
When a pattern is genuinely a single-purpose style you want everywhere, do not reach for @apply — make a real utility. In v4 that is the @utility directive.
@utility
@utility content-grid {
display: grid;
grid-template-columns:
[full-start] minmax(1rem, 1fr)
[content-start] minmax(0, 60rem) [content-end]
minmax(1rem, 1fr) [full-end];
}The payoff over @apply: a real utility is automatically variant-aware. You get md:content-grid and hover:content-grid with no extra work, because Tailwind registers it in the utility layer.
Functional utilities
Accept a value with --value() to build a whole family at once:
@utility tab-* {
tab-size: --value(integer);
}
/* tab-2, tab-4, tab-8 all now exist */When a JavaScript plugin still earns its place
- You need to read the resolved theme to generate many utilities programmatically (
matchUtilities). - You are distributing reusable behavior across projects — ship it as a plugin and load it with
@plugin "my-plugin";.
For everything local and simple, CSS-first @utility is less machinery and lives beside your tokens.
Example
When to use it
- A developer adds a text-shadow utility using @utility in CSS so it participates in Tailwind's variant system like hover:text-shadow-md.
- A design system publishes a Tailwind plugin that generates print-only utility classes for controlling page break behavior in reports.
- A team creates a scrollbar-hide utility via @utility to hide browser scrollbars on overflow containers without repeating vendor-prefixed CSS.
More examples
Custom utility via @utility
@utility registers each class with Tailwind's variant engine, so hover:text-shadow, dark:text-shadow, and md:text-shadow-sm all work automatically.
@import "tailwindcss";
@utility text-shadow {
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
@utility text-shadow-sm {
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
@utility text-shadow-none {
text-shadow: none;
}Scrollbar hide utility
A scrollbar-hide utility wraps vendor-prefixed scrollbar CSS into a single reusable class that can be applied like any built-in Tailwind utility.
@utility scrollbar-hide {
scrollbar-width: none; /* Firefox */
}
@utility scrollbar-hide::webkit-scrollbar {
display: none; /* Chrome, Safari */
}Plugin-based utility generation
A plugin reads custom theme values and generates corresponding utility classes dynamically, integrating with Tailwind's theme system for full config control.
// tailwind.config.js
const plugin = require('tailwindcss/plugin');
module.exports = {
plugins: [
plugin(({ addUtilities, theme }) => {
const shadows = theme('textShadow', {});
const utils = Object.entries(shadows).reduce((acc, [key, val]) => {
acc[`.text-shadow-${key}`] = { textShadow: val };
return acc;
}, {});
addUtilities(utils);
}),
],
theme: {
textShadow: { sm: '0 1px 2px rgba(0,0,0,.2)', md: '0 2px 4px rgba(0,0,0,.3)' },
},
}
Discussion