tailwind-tree
Version:
A utility for writing deeply nested and composable Tailwind CSS classes using an expressive tree structure, supporting responsive and interactive variants for Tailwind v3 and v4.
217 lines (157 loc) • 5.98 kB
Markdown
<div align="center">
<a href="https://github.com/shervin-ghajar/tailwind-tree">
<img src="https://raw.githubusercontent.com/shervin-ghajar/tailwind-tree/main/packages/shared/src/assets/logo-with-title.png" alt="tailwind-tree" style="max-width: 100%; height: 350px;">
</a>
</div>
# Tailwind Tree
[](https://www.npmjs.com/package/tailwind-tree)
[](https://www.npmjs.com/package/tailwind-tree)
[](LICENSE)
**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**.
## ✨ Features
- ✅ 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`](https://www.npmjs.com/package/tailwind-merge)
## 📦 Installation
```bash
pnpm add tailwind-tree
# or
npm install tailwind-tree
# or
yarn add tailwind-tree
```
## 🚀 Usage
Instead of manually writing long utility strings, use `twTree` for cleaner, conditional, deeply nested Tailwind class composition.
### ✅ Traditional Approach
```html
<div class="bg-amber-500 text-nowrap hover:bg-slate-600 hover:text-clip md:focus:text-blue-700" />
```
### 🌲 Using `twTree`
```ts
import { twTree } from 'tailwind-tree';
<div
className={twTree([
'bg-amber-500 text-nowrap',
{
hover: ['bg-slate-600', 'text-clip'],
md: [{ focus: ['text-blue-700'] }],
},
])}
/>;
```
## 🧩 Complex Example
```ts
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
## ⚙️ Tailwind Integration
> `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:
## 🧪 Tailwind v3 Setup (using `@tailwind-tree/extractor`)
Use the official extractor to enable precise class extraction:
### 1. Install the extractor
```bash
pnpm add -D @tailwind-tree/extractor
```
### 2. Configure Tailwind
```ts
// 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.
## ⚙️ Tailwind v4 Setup (using `@tailwind-tree/vite-plugin`)
Since Tailwind v4 removed extractors, use the official plugin to inject safelisted classes:
### 1. Install the plugin
```bash
pnpm add -D @tailwind-tree/vite-plugin
```
### 2. Add it to your Vite config
```ts
// vite.config.ts
import react from '@vitejs/plugin-react';
import tailwindcss from '@tailwindcss/vite';
import { twTreePlugin } from '@tailwind-tree/vite-plugin';
export default defineConfig({
plugins: [
react(),
twTreePlugin(), // <--- this adds all twTree classes to Tailwind safelist
tailwindcss(),
],
});
```
> 🧠 **Note:** Tailwind v4 may still generate **redundant classes** because it scans all string content. This is a limitation in Tailwind itself, not `twTree`.
## 🛠️ Options
The `twTree` function accepts a second `options` parameter:
```ts
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 |
### Example
```ts
twTree(['bg-red-500', { hover: ['bg-red-600'] }], {
merge: false,
prefix: 'tw-',
});
// → "tw-bg-red-500 tw-hover:bg-red-600"
```
## 📚 Related Packages
| Package | Description |
| ---------------------------------------------------------------------------------------- | ----------------------------------------------- |
| [`tailwind-tree`](https://www.npmjs.com/package/tailwind-tree) | Core `twTree` logic for nested class generation |
| [`@tailwind-tree/extractor`](https://www.npmjs.com/package/@tailwind-tree/extractor) | Tailwind v3 content extractor |
| [`@tailwind-tree/vite-plugin`](https://www.npmjs.com/package/@tailwind-tree/vite-plugin) | Tailwind v4 Vite plugin for safelisting classes |
## 📜 License
MIT © [Shervin Ghajar](https://github.com/shervin-ghajar)
Made with 💙 by [@shervin-ghajar](https://github.com/shervin-ghajar)