You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+28-9Lines changed: 28 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -11,7 +11,7 @@ It evolves the concept of Variant APIs (like [cva](https://cva.style/)) by intro
11
11
- 🎨 **Unified API** - Seamlessly blends static Tailwind classes and dynamic inline styles into one cohesive interface.
12
12
- 🧩 **Trait System** - Solves combinatorial explosion by treating states as stackable, non-exclusive layers.
13
13
- 🎯 **Scoped Styling** - Context-aware styling using data attributes - no React Context required (RSC friendly).
14
-
- ⚡ **JIT Optimized** - Prevents CSS bundle bloat by intelligently routing arbitrary values to inline styles.
14
+
- ⚡ **JIT Conscious** - Designed for Tailwind JIT: utilities stay as class strings, while truly dynamic values can be expressed as inline styles.
15
15
- 🔒 **Type-Safe** - Best-in-class TypeScript support with automatic prop inference.
16
16
- 📦 **Minimal Overhead** - Ultra-lightweight runtime with only `clsx` and `tailwind-merge` as dependencies.
17
17
@@ -82,28 +82,41 @@ button({ w: "w-full" });
82
82
83
83
### Interpolated Variants (Dynamic Props)
84
84
85
-
Interpolated variants provide a **Unified API** that bridges the gap between static Tailwind classes and dynamic inline styles. You can pass arbitrary values (handled as inline styles) or utility strings (handled as static classes) through a single prop, without breaking Tailwind's JIT compilation.
85
+
Interpolated variants provide a **Unified API** that bridges static Tailwind classes and dynamic inline styles. A dynamic resolver can return either:
86
+
87
+
- a **Tailwind class string** (static utility), or
88
+
- an object containing **className and/or style** (inline styles and optional utilities)
89
+
90
+
This is **JIT-friendly by design**, as long as the class strings you return are statically enumerable (i.e. appear in your source code).
91
+
For truly unbounded values (e.g. pixel sizes), prefer returning style to avoid relying on arbitrary-value class generation.
86
92
87
93
```typescript
88
94
const button =windCtrl({
89
95
dynamic: {
90
-
//⚡ JIT Friendly Pattern:
91
-
// Numbers -> Inline styles (bypassing JIT)
92
-
// Strings -> Static classes (scanned by JIT)
96
+
//Recommended pattern:
97
+
//- Numbers -> inline styles (unbounded values)
98
+
//- Strings -> Tailwind utilities (must be statically enumerable for JIT)
> **Note on Tailwind JIT**: Tailwind only generates CSS for class names it can statically detect in your source. Avoid constructing class strings dynamically (e.g. "`w-`" + `size`) unless you safelist them in your Tailwind config.
110
+
103
111
### Traits (Stackable States)
104
112
105
113
Traits are non-exclusive, stackable layers of state. Unlike `variants` (which are mutually exclusive), multiple traits can be active simultaneously. This declarative approach solves the "combinatorial explosion" problem often seen with `compoundVariants`.
106
114
115
+
Traits are **non-exclusive, stackable modifiers**. Unlike variants (mutually exclusive design choices), multiple traits can be active at the same time. This is a practical way to model boolean-like component states (e.g. `loading`, `disabled`, `glass`) without exploding compoundVariants.
116
+
117
+
When multiple traits generate conflicting utilities, Tailwind’s “last one wins” rule applies (via `tailwind-merge`).
118
+
If ordering matters, prefer the **array form** to make precedence explicit.
119
+
107
120
```typescript
108
121
const button =windCtrl({
109
122
traits: {
@@ -113,10 +126,10 @@ const button = windCtrl({
113
126
},
114
127
});
115
128
116
-
// Usage - Array form (Clean & Type-safe)
129
+
// Usage - Array form (explicit precedence; recommended when conflicts are possible)
117
130
button({ traits: ["loading", "glass"] });
118
131
119
-
// Usage - Object form (Great for boolean props)
132
+
// Usage - Object form (convenient for boolean props; order is not intended to be meaningful)
-**Tailwind JIT:** Tailwind only generates CSS for class names it can statically detect. Avoid constructing class strings dynamically unless you safelist them.
188
+
-**Traits precedence:** If trait order matters, use the array form (`traits: ["a", "b"]`) to make precedence explicit.
189
+
-**SSR/RSC:** Keep dynamic resolvers pure (same input → same output) to avoid hydration mismatches.
0 commit comments