or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

conditional-value-utilities.mdindex.mdproperty-definition.mdruntime-sprinkles.mdsprinkles-creation.md

sprinkles-creation.mddocs/

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

```