0
# Sprinkles Creation
1
2
Transform property definitions into type-safe utility functions that generate CSS class names. Supports both build-time and runtime usage patterns.
3
4
## Capabilities
5
6
### createSprinkles
7
8
Creates a type-safe function for accessing your defined properties. You can provide as many collections of properties as you like.
9
10
```typescript { .api }
11
/**
12
* Creates a type-safe function for accessing defined properties
13
* @param config - Variable number of property configuration objects from defineProperties
14
* @returns SprinklesFn with static properties Set
15
*/
16
function createSprinkles<Args extends ReadonlyArray<SprinklesProperties>>(
17
...config: Args
18
): SprinklesFn<Args>;
19
20
/**
21
* The sprinkles function type with properties introspection
22
*/
23
type SprinklesFn<Args extends ReadonlyArray<SprinklesProperties>> = ((
24
props: SprinkleProps<Args>
25
) => string) & { properties: Set<keyof SprinkleProps<Args>> };
26
27
/**
28
* Combined props type from all provided property configurations
29
*/
30
type SprinkleProps<Args extends ReadonlyArray<any>> = Args extends [
31
infer L,
32
...infer R
33
]
34
? (L extends SprinklesProperties ? ChildSprinkleProps<L['styles']> : never) &
35
SprinkleProps<R>
36
: {};
37
```
38
39
### Properties Introspection
40
41
The sprinkles function exposes a static `properties` key that lets you check whether a given property can be handled by the function.
42
43
```typescript { .api }
44
/**
45
* Static property set for introspection
46
*/
47
sprinkles.properties: Set<keyof SprinkleProps<Args>>;
48
49
/**
50
* Check if a property is handled by the sprinkles function
51
*/
52
sprinkles.properties.has(propertyName: string): boolean;
53
```
54
55
## Usage Examples
56
57
**Basic sprinkles creation:**
58
59
```typescript
60
import { defineProperties, createSprinkles } from "@vanilla-extract/sprinkles";
61
62
const responsiveProperties = defineProperties({
63
conditions: {
64
mobile: {},
65
tablet: { '@media': 'screen and (min-width: 768px)' },
66
desktop: { '@media': 'screen and (min-width: 1024px)' }
67
},
68
defaultCondition: 'mobile',
69
properties: {
70
display: ['none', 'flex', 'block'],
71
flexDirection: ['row', 'column'],
72
padding: {
73
small: '8px',
74
medium: '16px',
75
large: '24px'
76
}
77
}
78
});
79
80
const colorProperties = defineProperties({
81
conditions: {
82
lightMode: {},
83
darkMode: { '@media': '(prefers-color-scheme: dark)' }
84
},
85
defaultCondition: 'lightMode',
86
properties: {
87
color: {
88
primary: '#007bff',
89
secondary: '#6c757d'
90
},
91
background: {
92
surface: '#ffffff',
93
elevated: '#f8f9fa'
94
}
95
}
96
});
97
98
// Create sprinkles function from multiple property sets
99
export const sprinkles = createSprinkles(
100
responsiveProperties,
101
colorProperties
102
);
103
```
104
105
**Static usage in .css.ts files:**
106
107
```typescript
108
import { sprinkles } from './sprinkles.css';
109
110
// Basic static usage
111
export const container = sprinkles({
112
display: 'flex',
113
padding: 'medium',
114
color: 'primary'
115
});
116
117
// Conditional styling
118
export const responsiveContainer = sprinkles({
119
display: 'block',
120
flexDirection: {
121
mobile: 'column',
122
desktop: 'row'
123
},
124
background: {
125
lightMode: 'surface',
126
darkMode: 'elevated'
127
}
128
});
129
130
// Responsive array notation
131
export const spacedContainer = sprinkles({
132
display: 'flex',
133
padding: ['small', 'medium', 'large'] // mobile, tablet, desktop
134
});
135
```
136
137
**Runtime usage:**
138
139
```typescript
140
import { sprinkles } from './sprinkles.css';
141
142
// Dynamic runtime usage
143
function createDynamicStyles(isColumn: boolean, theme: 'light' | 'dark') {
144
return sprinkles({
145
display: 'flex',
146
flexDirection: isColumn ? 'column' : 'row',
147
background: theme === 'dark' ? 'elevated' : 'surface'
148
});
149
}
150
151
// Conditional runtime styling
152
const flexDirection = Math.random() > 0.5 ? 'column' : 'row';
153
const dynamicClass = sprinkles({
154
display: 'flex',
155
flexDirection
156
});
157
```
158
159
**Combining with vanilla-extract styles:**
160
161
```typescript
162
import { style } from '@vanilla-extract/css';
163
import { sprinkles } from './sprinkles.css';
164
165
// Combine sprinkles with custom styles
166
export const customContainer = style([
167
sprinkles({
168
display: 'flex',
169
padding: 'medium'
170
}),
171
{
172
':hover': {
173
outline: '2px solid currentColor'
174
},
175
'::before': {
176
content: '""',
177
display: 'block'
178
}
179
}
180
]);
181
```
182
183
**Using in vanilla-extract selectors:**
184
185
```typescript
186
import { globalStyle } from '@vanilla-extract/css';
187
import { sprinkles } from './sprinkles.css';
188
189
const cardContainer = sprinkles({
190
padding: 'medium',
191
background: 'surface'
192
});
193
194
// Sprinkles can be used in selectors
195
globalStyle(`${cardContainer} *`, {
196
boxSizing: 'border-box'
197
});
198
199
globalStyle(`${cardContainer}:hover`, {
200
transform: 'scale(1.02)'
201
});
202
```
203
204
**Properties introspection:**
205
206
```typescript
207
import { sprinkles } from './sprinkles.css';
208
209
// Check if property is supported
210
console.log(sprinkles.properties.has('padding')); // true
211
console.log(sprinkles.properties.has('fontSize')); // false
212
213
// Get all supported properties
214
const allProperties = Array.from(sprinkles.properties);
215
console.log(allProperties); // ['display', 'flexDirection', 'padding', 'color', 'background']
216
217
// Useful for building Box components
218
function Box({ children, ...props }) {
219
const sprinkleProps = {};
220
const otherProps = {};
221
222
for (const [key, value] of Object.entries(props)) {
223
if (sprinkles.properties.has(key)) {
224
sprinkleProps[key] = value;
225
} else {
226
otherProps[key] = value;
227
}
228
}
229
230
return (
231
<div className={sprinkles(sprinkleProps)} {...otherProps}>
232
{children}
233
</div>
234
);
235
}
236
```
237
238
**Error handling:**
239
240
```typescript
241
// Development-time error handling
242
try {
243
const invalidClass = sprinkles({
244
display: 'invalid-value' // Error: "display" has no value "invalid-value"
245
});
246
} catch (error) {
247
console.error(error.message); // SprinklesError with helpful message
248
}
249
250
try {
251
const noDefault = sprinkles({
252
color: { desktop: 'primary' } // Error if no default condition set
253
});
254
} catch (error) {
255
console.error(error.message); // Error about missing default condition
256
}
257
```
258
259
## Type Safety
260
261
The sprinkles function provides full type safety:
262
263
```typescript
264
const sprinkles = createSprinkles(/* ... */);
265
266
// TypeScript will enforce valid property names and values
267
const validClass = sprinkles({
268
display: 'flex', // ✓ Valid
269
padding: 'medium', // ✓ Valid
270
flexDirection: {
271
mobile: 'column', // ✓ Valid condition and value
272
desktop: 'row' // ✓ Valid condition and value
273
}
274
});
275
276
// These would cause TypeScript errors:
277
const invalidClass = sprinkles({
278
display: 'invalid', // ✗ Invalid value
279
unknownProp: 'value', // ✗ Unknown property
280
flexDirection: {
281
invalidCondition: 'row' // ✗ Invalid condition
282
}
283
});
284
```
285
286
## Error Handling and Validation
287
288
Sprinkles provides runtime validation with detailed error messages in development mode:
289
290
### SprinklesError
291
292
```typescript { .api }
293
/**
294
* Custom error class for sprinkles validation failures
295
*/
296
class SprinklesError extends Error {
297
constructor(message: string);
298
name: 'SprinklesError';
299
}
300
```
301
302
### Common Error Scenarios
303
304
**Invalid property values:**
305
306
```typescript
307
try {
308
const className = sprinkles({
309
display: 'invalid-value' // Error: "display" has no value "invalid-value"
310
});
311
} catch (error) {
312
console.error(error.name); // 'SprinklesError'
313
console.error(error.message); // Detailed validation message
314
}
315
```
316
317
**Missing default condition:**
318
319
```typescript
320
// If defineProperties has defaultCondition: false
321
try {
322
const className = sprinkles({
323
display: 'flex' // Error: no default condition specified
324
});
325
} catch (error) {
326
console.error(error.message); // Must specify conditions explicitly
327
}
328
```
329
330
**Invalid conditions:**
331
332
```typescript
333
try {
334
const className = sprinkles({
335
display: {
336
invalidCondition: 'flex' // Error: unknown condition
337
}
338
});
339
} catch (error) {
340
console.error(error.message); // Condition validation error
341
}
342
```
343
344
### Development vs Production Behavior
345
346
- **Development**: Full validation with detailed error messages
347
- **Production**: Minimal validation for performance
348
- **Runtime**: Always validates when using createRuntimeSprinkles
349
350
### Error Recovery Patterns
351
352
```typescript
353
function safeSprinkles(props: any, fallback = '') {
354
try {
355
return sprinkles(props);
356
} catch (error) {
357
if (error.name === 'SprinklesError') {
358
console.warn('Sprinkles validation error:', error.message);
359
return fallback;
360
}
361
throw error; // Re-throw non-sprinkles errors
362
}
363
}
364
365
// Usage with graceful fallback
366
const className = safeSprinkles({
367
display: userInput, // Potentially invalid
368
padding: 'medium'
369
}, 'fallback-class');
370
```