0
# Core Variant API
1
2
The core variant API provides the main functionality for creating styled components with variants, slots, compound variants, and default values. This is the primary interface for building reusable component styles.
3
4
## Main Functions
5
6
### tv
7
8
The primary function for creating variant-enabled styled components.
9
10
```typescript { .api }
11
const tv: TV;
12
```
13
14
The tv function accepts a configuration object and returns a styled component function that can be called with variant props to generate class names.
15
16
### createTV
17
18
Creates a custom tv instance with specific configuration.
19
20
```typescript { .api }
21
function createTV(config: TVConfig): TV;
22
```
23
24
**Parameters:**
25
- `config` - Configuration object for tailwind-merge integration
26
27
**Returns:** A tv function instance with the specified configuration
28
29
## TV Configuration Options
30
31
The tv function accepts a configuration object with the following options:
32
33
```typescript { .api }
34
interface TVOptions<V, S, B, EV, ES> {
35
extend?: TVReturnType;
36
base?: B;
37
slots?: S;
38
variants?: V;
39
compoundVariants?: TVCompoundVariants<V, S, B, EV, ES>[];
40
compoundSlots?: TVCompoundSlots<V, S, B>[];
41
defaultVariants?: TVDefaultVariants<V, S, EV, ES>;
42
}
43
```
44
45
### base
46
47
Base classes applied to all variants of the component.
48
49
```typescript
50
const button = tv({
51
base: "font-medium rounded-lg transition-colors focus:outline-none focus:ring-2"
52
});
53
```
54
55
### variants
56
57
Named variant groups with their corresponding classes.
58
59
```typescript
60
const button = tv({
61
base: "font-medium rounded-lg",
62
variants: {
63
color: {
64
primary: "bg-blue-500 text-white hover:bg-blue-600",
65
secondary: "bg-gray-500 text-white hover:bg-gray-600",
66
danger: "bg-red-500 text-white hover:bg-red-600",
67
},
68
size: {
69
sm: "px-3 py-1.5 text-sm",
70
md: "px-4 py-2 text-base",
71
lg: "px-6 py-3 text-lg",
72
},
73
disabled: {
74
true: "opacity-50 cursor-not-allowed",
75
false: "cursor-pointer",
76
},
77
},
78
});
79
```
80
81
### slots
82
83
Named component parts that can each have their own styling variants.
84
85
```typescript
86
const card = tv({
87
slots: {
88
base: "rounded-lg border shadow-sm",
89
header: "px-6 py-4 border-b",
90
body: "px-6 py-4",
91
footer: "px-6 py-4 border-t bg-gray-50",
92
},
93
variants: {
94
size: {
95
sm: {
96
base: "max-w-sm",
97
header: "px-4 py-2 text-sm",
98
body: "px-4 py-2 text-sm",
99
footer: "px-4 py-2 text-sm",
100
},
101
lg: {
102
base: "max-w-4xl",
103
header: "px-8 py-6 text-xl",
104
body: "px-8 py-6",
105
footer: "px-8 py-6",
106
},
107
},
108
},
109
});
110
111
// Usage with slots
112
const { base, header, body, footer } = card({ size: "lg" });
113
```
114
115
### compoundVariants
116
117
Conditional styles applied when specific variant combinations are active.
118
119
```typescript
120
const button = tv({
121
base: "font-medium rounded-lg",
122
variants: {
123
color: {
124
primary: "bg-blue-500 text-white",
125
secondary: "bg-gray-500 text-white",
126
},
127
size: {
128
sm: "px-3 py-1.5 text-sm",
129
lg: "px-6 py-3 text-lg",
130
},
131
},
132
compoundVariants: [
133
{
134
color: "primary",
135
size: "lg",
136
class: "shadow-lg shadow-blue-500/25",
137
},
138
{
139
color: ["primary", "secondary"],
140
size: "sm",
141
class: "font-semibold",
142
},
143
],
144
});
145
```
146
147
### compoundSlots
148
149
Conditional slot styles applied when specific variant combinations are active.
150
151
```typescript
152
const card = tv({
153
slots: {
154
base: "rounded-lg border",
155
header: "px-6 py-4 border-b",
156
},
157
variants: {
158
color: {
159
primary: { base: "border-blue-200" },
160
danger: { base: "border-red-200" },
161
},
162
},
163
compoundSlots: [
164
{
165
color: "primary",
166
slots: ["header"],
167
class: "bg-blue-50 text-blue-900",
168
},
169
],
170
});
171
```
172
173
### defaultVariants
174
175
Default variant values applied when no specific variants are provided.
176
177
```typescript
178
const button = tv({
179
variants: {
180
color: {
181
primary: "bg-blue-500",
182
secondary: "bg-gray-500",
183
},
184
size: {
185
sm: "text-sm px-3 py-1.5",
186
md: "text-base px-4 py-2",
187
},
188
},
189
defaultVariants: {
190
color: "primary",
191
size: "md",
192
},
193
});
194
195
// Uses default variants (primary, md)
196
const defaultButton = button();
197
```
198
199
### extend
200
201
Compose and extend existing tv components.
202
203
```typescript
204
const baseButton = tv({
205
base: "font-medium rounded-lg",
206
variants: {
207
size: {
208
sm: "px-3 py-1.5 text-sm",
209
md: "px-4 py-2 text-base",
210
},
211
},
212
});
213
214
const iconButton = tv({
215
extend: baseButton,
216
base: "inline-flex items-center gap-2",
217
variants: {
218
iconPosition: {
219
left: "flex-row",
220
right: "flex-row-reverse",
221
},
222
},
223
});
224
```
225
226
## Usage Examples
227
228
### Basic Component
229
230
```typescript
231
const alert = tv({
232
base: "p-4 rounded-md border",
233
variants: {
234
variant: {
235
info: "bg-blue-50 border-blue-200 text-blue-800",
236
success: "bg-green-50 border-green-200 text-green-800",
237
warning: "bg-yellow-50 border-yellow-200 text-yellow-800",
238
error: "bg-red-50 border-red-200 text-red-800",
239
},
240
},
241
defaultVariants: {
242
variant: "info",
243
},
244
});
245
246
// Usage
247
const infoAlert = alert(); // Uses default 'info' variant
248
const errorAlert = alert({ variant: "error" });
249
```
250
251
### Multi-Slot Component
252
253
```typescript
254
const modal = tv({
255
slots: {
256
overlay: "fixed inset-0 bg-black/50 flex items-center justify-center",
257
content: "bg-white rounded-lg shadow-xl max-w-md w-full mx-4",
258
header: "px-6 py-4 border-b border-gray-200",
259
body: "px-6 py-4",
260
footer: "px-6 py-4 border-t border-gray-200 flex justify-end gap-3",
261
},
262
variants: {
263
size: {
264
sm: {
265
content: "max-w-sm",
266
header: "px-4 py-3 text-sm",
267
body: "px-4 py-3 text-sm",
268
footer: "px-4 py-3",
269
},
270
lg: {
271
content: "max-w-2xl",
272
header: "px-8 py-6 text-xl",
273
body: "px-8 py-6",
274
footer: "px-8 py-6",
275
},
276
},
277
},
278
});
279
280
// Usage
281
const { overlay, content, header, body, footer } = modal({ size: "lg" });
282
```
283
284
## Type Definitions
285
286
```typescript { .api }
287
type TVReturnType<V extends TVVariants<S>, S extends TVSlots, B extends ClassValue, EV extends TVVariants<ES>, ES extends TVSlots, E extends TVReturnType = undefined> = {
288
(props?: TVProps<V, S, EV, ES>): HasSlots<S, ES> extends true
289
? {
290
[K in keyof (ES extends undefined ? {} : ES)]: (slotProps?: TVProps<V, S, EV, ES>) => string;
291
} & {
292
[K in keyof (S extends undefined ? {} : S)]: (slotProps?: TVProps<V, S, EV, ES>) => string;
293
} & {
294
[K in TVSlotsWithBase<{}, B>]: (slotProps?: TVProps<V, S, EV, ES>) => string;
295
}
296
: string;
297
} & TVReturnProps<V, S, B, EV, ES, E>;
298
299
type TVProps<V extends TVVariants<S>, S extends TVSlots, EV extends TVVariants<ES>, ES extends TVSlots> =
300
EV extends undefined
301
? V extends undefined
302
? ClassProp<ClassValue>
303
: {
304
[K in keyof V]?: StringToBoolean<keyof V[K]> | undefined;
305
} & ClassProp<ClassValue>
306
: V extends undefined
307
? {
308
[K in keyof EV]?: StringToBoolean<keyof EV[K]> | undefined;
309
} & ClassProp<ClassValue>
310
: {
311
[K in keyof V | keyof EV]?:
312
| (K extends keyof V ? StringToBoolean<keyof V[K]> : never)
313
| (K extends keyof EV ? StringToBoolean<keyof EV[K]> : never)
314
| undefined;
315
} & ClassProp<ClassValue>;
316
317
type TVCompoundVariants<V extends TVVariants<S>, S extends TVSlots, B extends ClassValue, EV extends TVVariants<ES>, ES extends TVSlots> = Array<
318
{
319
[K in keyof V | keyof EV]?:
320
| (K extends keyof V ? StringToBoolean<keyof V[K]> : never)
321
| (K extends keyof EV ? StringToBoolean<keyof EV[K]> : never)
322
| (K extends keyof V ? StringToBoolean<keyof V[K]>[] : never);
323
} & ClassProp<SlotsClassValue<S, B> | ClassValue>
324
>;
325
326
type TVCompoundSlots<V extends TVVariants<S>, S extends TVSlots, B extends ClassValue> = Array<
327
V extends undefined
328
? {
329
slots: Array<TVSlotsWithBase<S, B>>;
330
} & ClassProp
331
: {
332
slots: Array<TVSlotsWithBase<S, B>>;
333
} & {
334
[K in keyof V]?: StringToBoolean<keyof V[K]> | StringToBoolean<keyof V[K]>[];
335
} & ClassProp
336
>;
337
338
type TVDefaultVariants<V extends TVVariants<S>, S extends TVSlots, EV extends TVVariants<ES>, ES extends TVSlots> = {
339
[K in keyof V | keyof EV]?:
340
| (K extends keyof V ? StringToBoolean<keyof V[K]> : never)
341
| (K extends keyof EV ? StringToBoolean<keyof EV[K]> : never);
342
};
343
```