Tailwind Tree is a utility designed for writing deeply nested, composable Tailwind CSS classes using a simple and expressive tree structure. It simplifies the management of complex class combinations with responsive and interactive variants, supporting both Tailwind v3 and Tailwind v4.
- ✅ Declarative nested syntax
- ✅ Full support for variants like
hover:,md:,focus:, etc. - ✅ Works with both Tailwind v3 and Tailwind v4
- ✅ Automatic safelist generation or extractor integration
- ✅ Seamless merging using
tailwind-merge
pnpm add tailwind-tree
# or
npm install tailwind-tree
# or
yarn add tailwind-treeInstead of manually writing long utility strings, use twTree for cleaner, conditional, deeply nested Tailwind class composition.
<div class="bg-amber-500 text-nowrap hover:bg-slate-600 hover:text-clip md:focus:text-blue-700" />import { twTree } from 'tailwind-tree';
<div
className={twTree([
'bg-amber-500 text-nowrap',
{
hover: 'bg-slate-600 text-clip',
md: { focus: 'text-blue-700' },
},
])}
/>;twTree([
'text-white',
isActive ? 'bg-green-500' : 'bg-green-300',
{
hover: [
'underline opacity-50',
isFocused ? 'bg-blue-200' : 'bg-blue-100',
{
active: 'scale-105 font-semibold',
},
],
focus: [
'ring-2',
{
visible: ['ring-green-500', isError ? 'ring-red-500' : 'ring-yellow-500'],
},
],
},
anotherCondition ? 'p-4' : 'p-2',
'font-bold tracking-wide',
]);Supports:
- Deep nesting of variants (
hover:active,focus:visible) - Ternaries and conditional logic
- Mixed string literals and arrays
twTree(...)must be integrated into the Tailwind build pipeline to ensure your classes are discovered and preserved during purging.
Choose the right setup based on your Tailwind version:
Use the official extractor to enable precise class extraction:
pnpm add -D @tailwind-tree/extractor// tailwind.config.js
import { extractTwTree } from '@tailwind-tree/extractor';
export default {
content: [
{
files: ['./src/**/*.{ts,tsx,js,jsx}'],
extract: extractTwTree(),
},
],
theme: {
extend: {},
},
plugins: [],
};✅ This approach eliminates redundant or missing classes by parsing twTree(...) directly.
Since Tailwind v4 removed extractors, use the official plugin to inject safelisted classes:
pnpm add -D @tailwind-tree/vite-plugin// vite.config.ts
import { twTreePlugin } from '@tailwind-tree/vite-plugin';
import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
react(),
twTreePlugin(), // <--- this adds all twTree classes to Tailwind safelist
tailwindcss(),
],
});After adding the plugin to your Vite configuration, you must include the following import in your main CSS file. This is essential for the plugin to function correctly.
@import 'tailwindcss';
@import '@tailwind-tree/vite-plugin/safelist'; // <--- add safelistThis import ensures that all classes generated by twTree(...) calls are included in the final build.
🧠 Note: Tailwind v4 may still generate redundant classes because it scans all string content. This is a limitation in Tailwind itself, not
twTree.
The twTree function accepts a second options parameter:
twTree(input, options?)| Option | Type | Default | Description |
|---|---|---|---|
merge |
boolean |
true |
Whether to apply tailwind-merge to deduplicate conflicting classes |
prefix |
string |
"" |
Prefix to prepend to every class name |
twTree(['bg-red-500', { hover: ['bg-red-600'] }], {
merge: false,
prefix: 'tw-',
});
// → "tw-bg-red-500 tw-hover:bg-red-600"| Package | Description |
|---|---|
tailwind-tree |
Core twTree logic for nested class generation |
@tailwind-tree/extractor |
Tailwind v3 content extractor |
@tailwind-tree/vite-plugin |
Tailwind v4 Vite plugin for safelisting classes |
MIT © Shervin Ghajar
Made with 💙 by @shervin-ghajar