Tailwind CSS Guide
Tailwind CSS Custom Utilities
Extend Tailwind with your own utilities using the @utility directive.
Last updated: October 2026 · Tested on Tailwind v4.0
Quick answer: Use @utility my-class { property: value; } in your CSS to create a custom utility. Unlike @apply, custom utilities work with all Tailwind variants (hover:, md:, dark:) automatically. This is the modern replacement for the v3 plugin API.
Your First Custom Utility
@utility text-shadow-sm {
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
@utility text-shadow-md {
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}
@utility text-shadow-lg {
text-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
Now use them like any Tailwind utility:
<h1 class="text-shadow-md">Heading with shadow</h1>
<p class="text-shadow-sm">Subtle text shadow</p>
Variants Work Automatically
This is the key difference from @apply. Custom utilities support every Tailwind variant:
<h1 class="text-shadow-sm md:text-shadow-md lg:text-shadow-lg">
Responsive text shadow
</h1>
<button class="text-shadow-sm hover:text-shadow-none">
Shadow disappears on hover
</button>
No extra work needed — Tailwind handles variant composition.
💡 Why this matters: In v3, custom utilities created via the plugin API needed manual variant handling. In v4, variants are free.
Practical Examples
Content visibility optimization:
@utility content-auto {
content-visibility: auto;
contain-intrinsic-size: 0 500px;
}
Custom scrollbar styling:
@utility scrollbar-thin {
scrollbar-width: thin;
scrollbar-color: #475569 transparent;
}
Text gradient:
@utility text-gradient {
background: linear-gradient(90deg, #3b82f6, #8b5cf6);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
Glass morphism:
@utility glass {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
Registering Theme Values
If your utility relies on theme tokens, register them in @theme so they appear in Tailwind's reference:
@theme {
--text-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.1);
--text-shadow-md: 0 2px 4px rgba(0, 0, 0, 0.15);
--text-shadow-lg: 0 4px 8px rgba(0, 0, 0, 0.2);
}
@utility text-shadow-* {
text-shadow: --value(--text-shadow-*);
}
The --value() function pulls the theme value into your utility. This is the modern, type-safe approach.
Migrating from v3 Plugins
v3 approach (JavaScript plugin):
// tailwind.config.js (v3)
const plugin = require('tailwindcss/plugin');
module.exports = {
plugins: [
plugin(function ({ addUtilities }) {
addUtilities({
'.text-shadow-sm': {
textShadow: '0 1px 2px rgba(0,0,0,0.1)',
},
});
}),
],
};
v4 approach (CSS @utility):
@utility text-shadow-sm {
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
Same result, 15 lines shorter, and it lives next to your other CSS.
Advanced: Multi-Property Utilities
Utilities can include many properties — they're just CSS:
@utility aspect-square {
aspect-ratio: 1 / 1;
}
@utility card-hover {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
@utility card-hover:hover {
transform: translateY(-4px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
}
Or use nesting to combine:
@utility card-hover {
transition: all 0.2s ease;
&:hover {
transform: translateY(-4px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
}
}
🎯 @utility vs @apply vs Plugin API
| Feature | @utility | @apply | v3 Plugin |
|---|---|---|---|
| Where it lives | CSS file | CSS file | JS config |
| Variants support | Automatic | Limited | Manual |
| Purpose | New utilities | Component classes | Plugins |
| Recommended in v4 | ✅ Yes | For components | Rarely |
🛡️ Best Practices
- Use @utility for new utilities and @apply for component classes.
- Register theme values in
@themewhen your utility depends on tokens. - Keep each utility focused on one CSS property group.
- Name utilities clearly:
card-hoverbeatsch. - Test custom utilities with variants to make sure they work as expected.
- Prefer CSS-native features before creating new utilities — don't reinvent what Tailwind already does.
Avoid over-engineering: If you find yourself writing 30 custom utilities, you might be working against Tailwind's philosophy. The framework already covers 95% of common cases. Only add utilities when you genuinely need something missing.
❓ Frequently Asked Questions
How do I create a custom utility in Tailwind v4?
Use the @utility directive in your CSS file: @utility my-class { property: value; }. This creates a new utility class that works with all Tailwind variants like hover: and md:.
What is the difference between @utility and @apply?
@apply combines existing Tailwind utilities into a CSS class. @utility creates a brand new utility class that doesn't exist in Tailwind. Use @apply for components and @utility for new utilities.
Do custom @utility classes support variants?
Yes. Every custom utility created with @utility supports all Tailwind variants automatically. You can use hover:my-utility, md:my-utility, dark:my-utility, etc.
How do I add custom utilities in Tailwind v3?
In v3, add them via the plugin API in tailwind.config.js: plugin(function({ addUtilities }) { addUtilities({ '.my-class': { property: 'value' } }) }). In v4, use the @utility directive in CSS.
Should I use @utility or a Tailwind plugin?
In Tailwind v4, prefer @utility. It's simpler, faster, and lives alongside your other CSS. The plugin API still exists but is mostly for third-party packages.
🎉 You've Completed the Tailwind Cluster!
You now have 12 pages covering every aspect of Tailwind CSS — from install to advanced customization. Each page links to the others, creating a powerful topical authority cluster.