0
# Emotion Integration
1
2
@keystone-ui/core provides re-exported Emotion functions to ensure consistent CSS-in-JS usage across the KeystoneJS ecosystem. These re-exports guarantee version compatibility and provide a single import source for Emotion functionality.
3
4
## Capabilities
5
6
### CSS Styling Function
7
8
Core CSS-in-JS styling function for creating dynamic styles with full TypeScript support.
9
10
```typescript { .api }
11
/**
12
* CSS-in-JS styling function from @emotion/react
13
* @param template - Template literal with CSS styles
14
* @param args - Interpolated values and functions
15
* @returns Serialized CSS styles for use with css prop
16
*/
17
function css(template: TemplateStringsArray, ...args: any[]): SerializedStyles;
18
19
/**
20
* CSS styling function for object-based styles
21
* @param styles - CSS styles as JavaScript object
22
* @returns Serialized CSS styles for use with css prop
23
*/
24
function css(styles: CSSObject): SerializedStyles;
25
```
26
27
**Usage Examples:**
28
29
```typescript
30
import { css, useTheme } from "@keystone-ui/core";
31
32
// Template literal styles
33
const buttonStyles = css`
34
padding: 12px 24px;
35
border-radius: 6px;
36
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
37
color: white;
38
border: none;
39
cursor: pointer;
40
41
&:hover {
42
transform: translateY(-2px);
43
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
44
}
45
`;
46
47
// Object-based styles with theme integration
48
function ThemedButton() {
49
const theme = useTheme();
50
51
const styles = css({
52
padding: theme.spacing.medium,
53
backgroundColor: theme.colors.linkColor,
54
color: theme.colors.background,
55
borderRadius: theme.radii.small,
56
border: 'none',
57
fontFamily: theme.typography.fontFamily.body,
58
fontSize: theme.typography.fontSize.medium,
59
fontWeight: theme.typography.fontWeight.medium,
60
cursor: 'pointer',
61
62
'&:hover': {
63
backgroundColor: theme.colors.linkHoverColor,
64
},
65
66
'&:focus': {
67
outline: 'none',
68
boxShadow: `0 0 0 2px ${theme.colors.focusRing}`,
69
}
70
});
71
72
return <button css={styles}>Themed Button</button>;
73
}
74
75
// Dynamic styles with interpolation
76
const getDynamicStyles = (isActive: boolean, theme: Theme) => css`
77
color: ${isActive ? theme.colors.linkColor : theme.colors.foreground};
78
font-weight: ${isActive ? theme.typography.fontWeight.bold : theme.typography.fontWeight.regular};
79
80
${isActive && `
81
&::after {
82
content: '';
83
position: absolute;
84
bottom: -2px;
85
left: 0;
86
right: 0;
87
height: 2px;
88
background: ${theme.colors.linkColor};
89
}
90
`}
91
`;
92
```
93
94
### JSX Pragma
95
96
JSX pragma function required for Emotion's CSS-in-JS functionality in older JSX runtime configurations.
97
98
```typescript { .api }
99
/**
100
* JSX pragma function for Emotion CSS-in-JS support
101
* @param type - React element type
102
* @param props - Element props including css prop
103
* @param children - Child elements
104
* @returns React element with Emotion styles applied
105
*/
106
function jsx(type: any, props: any, ...children: any[]): any;
107
```
108
109
**Usage Examples:**
110
111
```typescript
112
/** @jsxRuntime classic */
113
/** @jsx jsx */
114
import { jsx, css } from "@keystone-ui/core";
115
116
// Component using jsx pragma (legacy)
117
function LegacyComponent() {
118
return (
119
<div css={css`
120
padding: 16px;
121
background: #f5f5f5;
122
`}>
123
Content with Emotion styles
124
</div>
125
);
126
}
127
128
// Modern usage with automatic JSX runtime (recommended)
129
import { css } from "@keystone-ui/core";
130
131
function ModernComponent() {
132
return (
133
<div css={css`
134
padding: 16px;
135
background: #f5f5f5;
136
`}>
137
Content with Emotion styles
138
</div>
139
);
140
}
141
```
142
143
### CSS Keyframes Animation
144
145
Function for creating CSS keyframe animations with Emotion.
146
147
```typescript { .api }
148
/**
149
* Creates CSS keyframes for animations
150
* @param template - Template literal with keyframe definitions
151
* @param args - Interpolated values
152
* @returns Keyframes object for use in animation properties
153
*/
154
function keyframes(template: TemplateStringsArray, ...args: any[]): Keyframes;
155
156
/**
157
* Creates CSS keyframes from object definition
158
* @param keyframeObject - Object with keyframe percentages and styles
159
* @returns Keyframes object for use in animation properties
160
*/
161
function keyframes(keyframeObject: Record<string, CSSObject>): Keyframes;
162
```
163
164
**Usage Examples:**
165
166
```typescript
167
import { keyframes, css, useTheme } from "@keystone-ui/core";
168
169
// Fade in animation
170
const fadeIn = keyframes`
171
from {
172
opacity: 0;
173
transform: translateY(20px);
174
}
175
to {
176
opacity: 1;
177
transform: translateY(0);
178
}
179
`;
180
181
// Pulse animation with theme colors
182
function PulseLoader() {
183
const theme = useTheme();
184
185
const pulse = keyframes`
186
0%, 100% {
187
background-color: ${theme.colors.linkColor};
188
transform: scale(1);
189
}
190
50% {
191
background-color: ${theme.colors.linkHoverColor};
192
transform: scale(1.1);
193
}
194
`;
195
196
const styles = css`
197
width: 40px;
198
height: 40px;
199
border-radius: 50%;
200
animation: ${pulse} 1.5s ease-in-out infinite;
201
`;
202
203
return <div css={styles} />;
204
}
205
206
// Object-based keyframes
207
const slideIn = keyframes({
208
'0%': {
209
transform: 'translateX(-100%)',
210
opacity: 0
211
},
212
'100%': {
213
transform: 'translateX(0)',
214
opacity: 1
215
}
216
});
217
218
const slideInStyles = css`
219
animation: ${slideIn} 0.3s ease-out;
220
`;
221
```
222
223
### Global Styles Component
224
225
Component for applying global CSS styles to the entire application.
226
227
```typescript { .api }
228
/**
229
* Component for injecting global CSS styles
230
* @param props - Global styles configuration
231
* @returns JSX element that applies global styles
232
*/
233
function Global(props: GlobalProps): JSX.Element;
234
235
interface GlobalProps {
236
/** CSS styles to apply globally */
237
styles: CSSObject | SerializedStyles | string;
238
}
239
```
240
241
**Usage Examples:**
242
243
```typescript
244
import { Global, css, useTheme } from "@keystone-ui/core";
245
246
// Global reset styles
247
function GlobalReset() {
248
return (
249
<Global
250
styles={css`
251
* {
252
box-sizing: border-box;
253
}
254
255
body {
256
margin: 0;
257
padding: 0;
258
}
259
260
h1, h2, h3, h4, h5, h6 {
261
margin: 0;
262
}
263
`}
264
/>
265
);
266
}
267
268
// Theme-based global styles
269
function ThemedGlobalStyles() {
270
const theme = useTheme();
271
272
return (
273
<Global
274
styles={{
275
body: {
276
fontFamily: theme.typography.fontFamily.body,
277
fontSize: theme.typography.fontSize.medium,
278
lineHeight: theme.typography.leading.base,
279
color: theme.colors.foreground,
280
backgroundColor: theme.colors.background
281
},
282
283
'h1, h2, h3, h4, h5, h6': {
284
fontFamily: theme.typography.fontFamily.heading,
285
color: theme.colors.foregroundMuted
286
},
287
288
'a': {
289
color: theme.colors.linkColor,
290
'&:hover': {
291
color: theme.colors.linkHoverColor
292
}
293
}
294
}}
295
/>
296
);
297
}
298
```
299
300
### ClassNames Render Prop Component
301
302
Component providing render prop pattern for dynamic CSS class generation.
303
304
```typescript { .api }
305
/**
306
* Render prop component for dynamic class name generation
307
* @param props - ClassNames render prop configuration
308
* @returns Result of children render function
309
*/
310
function ClassNames(props: ClassNamesProps): ReactNode;
311
312
interface ClassNamesProps {
313
/** Render function receiving class name utilities */
314
children: (utilities: ClassNameUtilities) => ReactNode;
315
}
316
317
interface ClassNameUtilities {
318
/** Function to generate CSS class names from styles */
319
css: (...styles: (CSSObject | SerializedStyles)[]) => string;
320
/** CSS styling function */
321
cx: typeof css;
322
}
323
```
324
325
**Usage Examples:**
326
327
```typescript
328
import { ClassNames, useTheme } from "@keystone-ui/core";
329
330
// Dynamic class names with conditional styling
331
function ConditionalButton({ variant, isActive }) {
332
const theme = useTheme();
333
334
return (
335
<ClassNames>
336
{({ css, cx }) => (
337
<button
338
className={cx(
339
css({
340
padding: theme.spacing.medium,
341
border: 'none',
342
borderRadius: theme.radii.small,
343
fontFamily: theme.typography.fontFamily.body,
344
cursor: 'pointer'
345
}),
346
347
variant === 'primary' && css({
348
backgroundColor: theme.colors.linkColor,
349
color: theme.colors.background
350
}),
351
352
variant === 'secondary' && css({
353
backgroundColor: theme.colors.backgroundMuted,
354
color: theme.colors.foreground,
355
border: `1px solid ${theme.colors.border}`
356
}),
357
358
isActive && css({
359
transform: 'scale(0.95)',
360
opacity: 0.8
361
})
362
)}
363
>
364
Dynamic Button
365
</button>
366
)}
367
</ClassNames>
368
);
369
}
370
371
// Integration with external class libraries
372
function StyledComponent({ className }) {
373
return (
374
<ClassNames>
375
{({ css, cx }) => (
376
<div
377
className={cx(
378
className, // External classes
379
css` // Emotion styles
380
padding: 16px;
381
margin: 8px;
382
`
383
)}
384
>
385
Combined styling
386
</div>
387
)}
388
</ClassNames>
389
);
390
}
391
```
392
393
## TypeScript Integration
394
395
All Emotion functions include full TypeScript support with proper type inference:
396
397
```typescript
398
import { css, keyframes, Theme } from "@keystone-ui/core";
399
400
// Type-safe theme usage
401
const createThemedStyles = (theme: Theme) => css({
402
color: theme.colors.foreground, // ✓ Type-safe
403
fontSize: theme.typography.fontSize.large, // ✓ Type-safe
404
// invalidProperty: theme.nonexistent // ✗ TypeScript error
405
});
406
407
// Typed keyframes
408
const typedAnimation: Keyframes = keyframes`
409
from { opacity: 0; }
410
to { opacity: 1; }
411
`;
412
413
// Template literals with interpolation
414
const dynamicStyles = (isVisible: boolean) => css`
415
opacity: ${isVisible ? 1 : 0};
416
transition: opacity 0.2s ease;
417
`;
418
```
419
420
## Performance Considerations
421
422
### Style Caching
423
424
Emotion automatically caches generated styles for optimal performance:
425
426
```typescript
427
// Styles are cached by their serialized form
428
const cachedStyles = css`
429
color: red;
430
font-size: 16px;
431
`;
432
433
// Reusing the same styles won't regenerate CSS
434
const sameStyles = css`
435
color: red;
436
font-size: 16px;
437
`; // Uses cached version
438
```
439
440
### Bundle Size Optimization
441
442
The re-exported functions help minimize bundle size by ensuring only one Emotion version is included in the final bundle.
443
444
### Server-Side Rendering
445
446
All Emotion functions are fully compatible with server-side rendering when used within the @keystone-ui/core ecosystem.
447
448
## CSS Normalization
449
450
### Normalize Styles
451
452
Pre-built CSS normalization styles for consistent cross-browser rendering.
453
454
```typescript { .api }
455
/**
456
* CSS normalization styles based on normalize.css v8.0.1
457
* Provides consistent default styling across browsers
458
*/
459
const normalize: SerializedStyles;
460
```
461
462
**Usage Examples:**
463
464
```typescript
465
import { normalize, Global } from "@keystone-ui/core";
466
467
// Apply normalize globally
468
function App() {
469
return (
470
<>
471
<Global styles={normalize} />
472
<div>Your app content with normalized styles</div>
473
</>
474
);
475
}
476
477
// Combine with custom global styles
478
function AppWithCustomGlobals() {
479
return (
480
<>
481
<Global styles={[
482
normalize,
483
css`
484
body {
485
font-family: system-ui, sans-serif;
486
line-height: 1.6;
487
}
488
489
* {
490
box-sizing: border-box;
491
}
492
`
493
]} />
494
<div>Your app content</div>
495
</>
496
);
497
}
498
499
// Use with Core component (recommended)
500
import { Core } from "@keystone-ui/core";
501
502
function AppWithCore() {
503
return (
504
<Core>
505
{/* Core component automatically includes normalize when includeNormalize=true */}
506
<div>Your app content</div>
507
</Core>
508
);
509
}
510
```
511
512
The normalize styles include:
513
- Consistent box model defaults
514
- Form element styling normalization
515
- Typography baseline normalization
516
- Focus outline removal (replaced by theme-based focus indicators)
517
- Cross-browser compatibility fixes