@workday/canvas-kit-mcp 15.0.0-alpha.0051-next.0 → 15.0.0-alpha.0060-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,649 @@
1
+ ---
2
+ source_file: react/common/stories/mdx/Theming.mdx
3
+ live_url: https://workday.github.io/canvas-kit/react/common/stories/mdx/Theming
4
+ ---
5
+
6
+ <Meta title="Features/Theming/Overview" />
7
+
8
+ # Canvas Kit Theming Guide
9
+
10
+ ## Overview
11
+
12
+ Canvas Kit v14 introduces a significant shift in our approach to theming: we've moved away from
13
+ JavaScript-based theme objects to CSS variables. This change provides better performance, improved
14
+ developer experience, and greater flexibility for theming applications.
15
+
16
+ > **📌 Quick Start:**
17
+ >
18
+ > 1. **Import CSS variables once** at the root level of your application (e.g., in `index.css`)
19
+ > 2. **Override tokens at `:root`** for global theming — this is the recommended approach
20
+ > 3. **Use `CanvasProvider` scoped theming only** for specific scenarios like multi-brand sections
21
+ > or embedded components
22
+ >
23
+ > If your application renders within an environment that already imports these CSS variables, \*\*do
24
+ > not re-
25
+
26
+ <CanvasProvider theme={{canvas: {palette: {primary: {main: 'purple'}}}}}> <App /> </CanvasProvider>;
27
+
28
+ ````
29
+
30
+ This would use `chroma.js` to generate a palette based on the `main` color provided.
31
+
32
+ **Why we're moving away from this approach:**
33
+
34
+ - Performance overhead from JavaScript theme object processing
35
+ - Limited flexibility for complex theming scenarios
36
+ - Inconsistent cascade behavior
37
+
38
+ Any time `theme` is passed, the `CanvasProvider` would generate a palette and attach brand variables
39
+ via a `className` scoping those brand variables to a wrapping div. In order for us to provide a
40
+ better solution to theming that is scalable and is more aligned with our CSS variables, we changed
41
+ this approach.
42
+
43
+ **Note:** While we support theme overrides, we advise to use global theming via CSS Variables.
44
+
45
+ ## What is a Cascade Barrier?
46
+
47
+ When we say "cascade barrier", we're talking about how
48
+ [CSS cascades](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_cascade/Cascade) and takes
49
+ precedence. Take the following example:
50
+
51
+ ```css
52
+ :root {
53
+ --cnbvs-brand-primary-base: blue;
54
+ }
55
+
56
+ // the element with the class .my-app will have a higher specificity than root, creating a barrier where the CSS variables gets redefined and takes precedence over what is defined at root.
57
+ .my-app {
58
+ --cnvs-brand-primary-base: red;
59
+ }
60
+ ````
61
+
62
+ In the case of the `CanvasProvider` prior to v14, all our brand tokens where defined within a class
63
+ and scoped to the `div` that the `CanvasProvider` created. This meant that anything set on `:root`
64
+ or outside of the `CanvasProvider` would not be able to cascade down to the components within the
65
+ `CanvasProvider`.
66
+
67
+ If you provide a `theme` to the `CanvasProvider`, it will create a scoped theme. Note that in v14,
68
+ global CSS variables are the recommended way to theme Popups and Modals consistently.
69
+
70
+ ## Global vs Scoped Theming
71
+
72
+ Canvas Kit v14 supports two theming strategies: **global theming** and **scoped theming**.
73
+ Understanding the difference is important to avoid unexpected behavior.
74
+
75
+ ### Global Theming
76
+
77
+ Global theming applies CSS variables at the `:root` level, making them available throughout your
78
+ entire application. This is the **recommended approach** for most use cases.
79
+
80
+ ```css
81
+ @import '@workday/canvas-tokens-web/css/base/_variables.css';
82
+ :root {
83
+ // This is showing how you can change the value of a token at the root level of your application.
84
+ --cnvs-brand-primary-base: var(--cnvs-base-palette-magenta-600);
85
+ }
86
+ ```
87
+
88
+ ### Scoped Theming
89
+
90
+ Scoped theming applies CSS variables to a specific section of your application using the
91
+ `CanvasProvider` with either a `className` or `theme` prop. The theme only affects components within
92
+ that provider.
93
+
94
+ ```tsx
95
+ // Using the theme prop for scoped theming. This will set the [brand.primary.**] tokens to shades of purple.
96
+ <CanvasProvider theme={{canvas: {palette: {primary: {main: 'purple'}}}}}>
97
+ <ScopedSection />
98
+ </CanvasProvider>
99
+ ```
100
+
101
+ > **⚠️ Warning:** Scoped theming creates a cascade barrier that **will break global theming**. Any
102
+ > CSS variables defined at `:root` will be overridden by the scoped theme. Only the tokens
103
+ > explicitly defined in the `theme` prop will be changed - other tokens will use their default
104
+ > values, not your global overrides.
105
+
106
+ ### When to Use Scoped Theming
107
+
108
+ Only use scoped theming when you intentionally need a different theme for a specific section of your
109
+ application, such as:
110
+
111
+ - Embedding a Canvas Kit component in a third-party application with a different brand
112
+ - Creating a preview panel that shows components with different themes
113
+ - Supporting multi-tenant applications where sections have different branding
114
+
115
+ For all other cases, use global theming at `:root` to ensure consistent theming throughout your
116
+ application.
117
+
118
+ ## ✅ Preferred Approach (v14+)
119
+
120
+ Canvas Kit v14 promotes using CSS variables for theming, which can be applied in two ways:
121
+
122
+ ### Method 1: Global CSS Variables (Recommended)
123
+
124
+ Apply theming at the global level by importing CSS variable files and overriding values in your root
125
+ CSS:
126
+
127
+ ```css
128
+ /* index.css */
129
+ @import '@workday/canvas-tokens-web/css/base/_variables.css';
130
+ @import '@workday/canvas-tokens-web/css/system/_variables.css';
131
+ @import '@workday/canvas-tokens-web/css/brand/_variables.css';
132
+
133
+ :root {
134
+ /* Override brand primary colors */
135
+ --cnvs-brand-primary-base: var(--cnvs-base-palette-magenta-600);
136
+ --cnvs-brand-primary-light: var(--cnvs-base-palette-magenta-200);
137
+ --cnvs-brand-primary-lighter: var(--cnvs-base-palette-magenta-50);
138
+ --cnvs-brand-primary-lightest: var(--cnvs-base-palette-magenta-25);
139
+ --cnvs-brand-primary-dark: var(--cnvs-base-palette-magenta-700);
140
+ --cnvs-brand-primary-darkest: var(--cnvs-base-palette-magenta-800);
141
+ --cnvs-brand-primary-accent: var(--cnvs-base-palette-neutral-0);
142
+ }
143
+ ```
144
+
145
+ > **Note:** You should only
146
+
147
+ // You can import the CSS variables in a ts file or an index.css file. You do not need to do both.
148
+ import '@workday/canvas-tokens-web/css/base/\_variables.css'; import
149
+ '@workday/canvas-tokens-web/css/system/\_variables.css'; import
150
+ '@workday/canvas-tokens-web/css/brand/\_variables.css';
151
+
152
+ // Generate a class name that defines CSS variables const themedBrand = createStyles({
153
+ [brand.primary.accent]: base.neutral0, [brand.primary.darkest]: base.blue800, [brand.primary.dark]:
154
+ base.blue700, [brand.primary.base]: base.blue600, [brand.primary.light]: base.blue200,
155
+ [brand.primary.lighter]: base.blue50, [brand.primary.lightest]: base.blue25, })
156
+
157
+ <CanvasProvider className={themedBrand}>
158
+ <App/>
159
+ </CanvasProvider>
160
+ ```
161
+
162
+ ### Theming Modals and Dialogs
163
+
164
+ Previously, the `usePopupStack` hook created a CSS class name that was passed to our Popups. We
165
+ attached those theme styles to that class name. This allowed the theme to be available in our
166
+ Popups. But it also created a cascade barrier that blocked the global theme from being applied to
167
+ our Popup components. Because we now use global CSS variables, we no longer need this class name to
168
+ provide the global theme to Popups. But we have to remove this generated class name to allow the
169
+ global theme to be applied to Popups.
170
+
171
+ **Before in v13**
172
+
173
+ ```tsx
174
+ // When passing a theme to the Canvas Provider, the `usePopupStack` would grab the theme and generate a class to forward the theme to Modals and Dialogs. This would create a cascade barrier for any CSS variables defined at the root.
175
+ <CanvasProvider theme={{canvas: {palette: {primary: {main: 'blue'}}}}}>
176
+ <Modal>//... rest of modal code</Modal>
177
+ </CanvasProvider>
178
+ ```
179
+
180
+ **After in v14**
181
+
182
+ ```tsx
183
+ // If you wish to still theme you application and Modals, you can either define the CSS variables at the root level of your application or define a className and pass it to the CanvasProvider.
184
+ :root {
185
+ --cnvs-brand-primary-base: blue;
186
+ }
187
+
188
+ <CanvasProvider>
189
+ <Modal>//... rest of modal code</Modal>
190
+ </CanvasProvider>
191
+ ```
192
+
193
+ ## CSS Token Structure
194
+
195
+ Canvas Kit provides three layers of CSS variables.
196
+
197
+ ### Base Tokens (`base/_variables.css`)
198
+
199
+ Base tokens define foundation palette and design values.
200
+
201
+ ```css
202
+ --cnvs-base-palette-blue-600: oklch(0.5198 0.1782 256.11 / 1);
203
+ --cnvs-base-palette-magenta-600: oklch(0.534 0.183 344.19 / 1);
204
+ --cnvs-base-font-size-100: 1rem;
205
+ --cnvs-base-space-x4: calc(var(--cnvs-base-unit) * 4);
206
+ ```
207
+
208
+ ### Brand Tokens (`brand/_variables.css`)
209
+
210
+ Brand tokens define semantic color assignments.
211
+
212
+ ```css
213
+ --cnvs-brand-primary-base: var(--cnvs-base-palette-blue-600);
214
+ --cnvs-brand-primary-accent: var(--cnvs-base-palette-neutral-0);
215
+ --cnvs-brand-error-base: var(--cnvs-base-palette-red-600);
216
+ --cnvs-brand-success-base: var(--cnvs-base-palette-green-600);
217
+ ```
218
+
219
+ ### System Tokens (`system/_variables.css`)
220
+
221
+ System tokens define component-specific values.
222
+
223
+ ```css
224
+ --cnvs-sys-color-bg-primary-default: var(--cnvs-base-palette-blue-600);
225
+ --cnvs-sys-color-text-primary-default: var(--cnvs-base-palette-blue-600);
226
+ --cnvs-sys-space-x4: calc(var(--cnvs-base-unit) * 4);
227
+ ```
228
+
229
+ ## Practical Examples
230
+
231
+ ### Complete Brand Theming
232
+
233
+ ```css
234
+ /* themes/magenta-theme.css */
235
+ @import '@workday/canvas-tokens-web/css/base/_variables.css';
236
+ @import '@workday/canvas-tokens-web/css/system/_variables.css';
237
+ @import '@workday/canvas-tokens-web/css/brand/_variables.css';
238
+
239
+ :root {
240
+ /* Primary brand colors */
241
+ --cnvs-brand-primary-base: var(--cnvs-base-palette-magenta-600);
242
+ --cnvs-brand-primary-light: var(--cnvs-base-palette-magenta-200);
243
+ --cnvs-brand-primary-lighter: var(--cnvs-base-palette-magenta-50);
244
+ --cnvs-brand-primary-lightest: var(--cnvs-base-palette-magenta-25);
245
+ --cnvs-brand-primary-dark: var(--cnvs-base-palette-magenta-700);
246
+ --cnvs-brand-primary-darkest: var(--cnvs-base-palette-magenta-800);
247
+ --cnvs-brand-primary-accent: var(--cnvs-base-palette-neutral-0);
248
+ }
249
+ ```
250
+
251
+ ```tsx
252
+ import {createStyles} from '@workday/canvas-kit-styling';
253
+ import {brand, base, system} from '@workday/canvas-tokens-web';
254
+ import {CanvasProvider} from '@workday/canvas-kit-react/common';
255
+ import {Card} from '@workday/canvas-kit-react/card';
256
+ import {PrimaryButton} from '@workday/canvas-kit-react/button';
257
+
258
+ const customTheme = createStyles({
259
+ [brand.primary.base]: base.green600,
260
+ [brand.primary.dark]: base.green700,
261
+ [brand.primary.darkest]: base.green800,
262
+ [brand.common.focusOutline]: base.green600,
263
+ [system.color.fg.strong]: base.indigo900,
264
+ [system.color.border.container]: base.indigo300,
265
+ });
266
+
267
+ const App = () => {
268
+ return (
269
+ <CanvasProvider
270
+ theme={{
271
+ canvas: {
272
+ palette: {
273
+ primary: {
274
+ main: base.green600,
275
+ dark: base.green700,
276
+ darkest: base.green800,
277
+ light: base.green200,
278
+ lighter: base.green50,
279
+ lightest: base.green25,
280
+ contrast: base.neutral0,
281
+ },
282
+ },
283
+ },
284
+ }}
285
+ >
286
+ <Card>
287
+ <Card.Heading>Theming</Card.Heading>
288
+ <Card.Body>
289
+ <PrimaryButton>Theming</PrimaryButton>
290
+ <input />
291
+ </Card.Body>
292
+ </Card>
293
+ </CanvasProvider>
294
+ );
295
+ };
296
+
297
+ export const Theming = () => {
298
+ return (
299
+ <CanvasProvider className={customTheme}>
300
+ <App />
301
+ </CanvasProvider>
302
+ );
303
+ };
304
+ ```
305
+
306
+ ### Dark Mode Implementation
307
+
308
+ ```css
309
+ /* Dark mode theming */
310
+ [data-theme='dark'] {
311
+ --cnvs-sys-color-bg-default: var(--cnvs-base-palette-neutral-950);
312
+ --cnvs-sys-color-text-default: var(--cnvs-base-palette-neutral-50);
313
+ --cnvs-sys-color-border-container: var(--cnvs-base-palette-slate-700);
314
+ --cnvs-sys-color-bg-alt-default: var(--cnvs-base-palette-slate-800);
315
+ }
316
+ ```
317
+
318
+ ### RTL Support
319
+
320
+ Canvas Kit supports RTL out of the box. Our components are styled to use
321
+ [CSS logical properties](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_values).
322
+ If you want to add additional styles based on RTL, you can also use the `:dir`
323
+ [pseudo selector](https://developer.mozilla.org/en-US/docs/Web/CSS/:dir).
324
+
325
+ #### Setting RTL Direction
326
+
327
+ Use the native HTML `dir` attribute to set the text direction. The `CanvasProvider` accepts a `dir`
328
+ prop which sets this attribute on its wrapper element:
329
+
330
+ ```tsx
331
+ // Set RTL direction
332
+ <CanvasProvider dir="rtl">
333
+ <App />
334
+ </CanvasProvider>
335
+ ```
336
+
337
+ You can also set it on any HTML element:
338
+
339
+ ```tsx
340
+ <div dir="rtl">
341
+ <MyComponent />
342
+ </div>
343
+ ```
344
+
345
+ > **Note:** The `dir` attribute is the standard HTML way to set text direction. It's preferred over
346
+ > the deprecated `theme.canvas.direction` approach because it works natively with CSS logical
347
+ > properties and the `:dir()` pseudo-class.
348
+
349
+ #### Using CSS Logical Properties
350
+
351
+ CSS logical properties automatically adapt to the text direction. Use these instead of physical
352
+ properties:
353
+
354
+ ```css
355
+ /* Physical properties (don't adapt to RTL) */
356
+ .my-component {
357
+ margin-left: 1rem;
358
+ padding-right: 1rem;
359
+ border-left: 1px solid;
360
+ }
361
+
362
+ /* Logical properties (adapt to RTL automatically) */
363
+ .my-component {
364
+ margin-inline-start: 1rem;
365
+ padding-inline-end: 1rem;
366
+ border-inline-start: 1px solid;
367
+ }
368
+ ```
369
+
370
+ #### Conditional RTL Styles with `:dir()`
371
+
372
+ For styles that need to change based on direction (like rotating icons), use the `:dir()`
373
+ pseudo-class:
374
+
375
+ ```tsx
376
+ const rtlButtonStyles = createStyles({
377
+ ':dir(rtl)': {
378
+ svg: {
379
+ transform: 'rotate(180deg)',
380
+ },
381
+ },
382
+ });
383
+ ```
384
+
385
+ ```tsx
386
+ import React from 'react';
387
+ import {createStyles} from '@workday/canvas-kit-styling';
388
+
389
+ import {CanvasProvider} from '@workday/canvas-kit-react/common';
390
+ import {Card} from '@workday/canvas-kit-react/card';
391
+ import {PrimaryButton} from '@workday/canvas-kit-react/button';
392
+ import {FormField} from '@workday/canvas-kit-react/form-field';
393
+ import {TextInput} from '@workday/canvas-kit-react/text-input';
394
+ import {arrowRightSmallIcon} from '@workday/canvas-system-icons-web';
395
+ import {system} from '@workday/canvas-tokens-web';
396
+
397
+ const rtlStyles = createStyles({
398
+ paddingInlineStart: system.space.x16,
399
+ });
400
+
401
+ const rtlButtonStyles = createStyles({
402
+ ':dir(rtl)': {
403
+ svg: {
404
+ transform: 'rotate(180deg)',
405
+ },
406
+ },
407
+ });
408
+
409
+ const App = () => {
410
+ const [value, setValue] = React.useState('');
411
+
412
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
413
+ setValue(event.target.value);
414
+ };
415
+ return (
416
+ <Card>
417
+ <Card.Heading>RTL Support</Card.Heading>
418
+ <Card.Body cs={rtlStyles}>
419
+ <FormField>
420
+ <FormField.Label>Email</FormField.Label>
421
+ <FormField.Field>
422
+ <FormField.Input as={TextInput} onChange={handleChange} value={value} />
423
+ </FormField.Field>
424
+ </FormField>
425
+ <PrimaryButton cs={rtlButtonStyles} iconPosition="end" icon={arrowRightSmallIcon}>
426
+ RTL
427
+ </PrimaryButton>
428
+ </Card.Body>
429
+ </Card>
430
+ );
431
+ };
432
+
433
+ export const RTL = () => {
434
+ return (
435
+ <CanvasProvider dir="rtl">
436
+ <App />
437
+ </CanvasProvider>
438
+ );
439
+ };
440
+ ```
441
+
442
+ ### Resetting to Default Brand Theme
443
+
444
+ If you need to reset the theme in parts of your application, there's a few ways to do this. We
445
+ export a `defaultBranding` class that can be applied to the `CanvasProvider` which can wrap parts of
446
+ your application.
447
+
448
+ ```tsx
449
+ <CanvasProvider className={defaultBranding}>
450
+ <SomeSubComponent />
451
+ </CanvasProvider>
452
+ ```
453
+
454
+ > **Note:** Doing the following **will create a cascade barrier**. Only use this method if you
455
+ > intentionally want to override the default theme.
456
+
457
+ ## Migration Guide
458
+
459
+ ### Step 1: Identify Current Theme Usage
460
+
461
+ Find all instances of `CanvasProvider` with theme props in your application.
462
+
463
+ ```tsx
464
+ // Find these patterns:
465
+ <CanvasProvider theme={{canvas: {palette: {...}}}}>
466
+ ```
467
+
468
+ ### Step 2: Extract Theme Values
469
+
470
+ Convert JavaScript theme objects to CSS variable overrides.
471
+
472
+ ```tsx
473
+ // Old approach:
474
+ const theme = {
475
+ canvas: {
476
+ palette: {
477
+ primary: {
478
+ main: colors.greenApple400,
479
+ dark: colors.greenApple500,
480
+ }
481
+ }
482
+ }
483
+ };
484
+
485
+ // New approach - CSS variables:
486
+ :root {
487
+ --cnvs-brand-primary-base: var(--cnvs-base-palette-green-400);
488
+ --cnvs-brand-primary-dark: var(--cnvs-base-palette-green-500);
489
+ }
490
+ ```
491
+
492
+ ### Step 3: App Level Theming Usage
493
+
494
+ Replace theme-based `CanvasProvider` usage with CSS class-based theming.
495
+
496
+ ```tsx
497
+ // Before:
498
+ <CanvasProvider theme={customTheme}>
499
+ <App />
500
+ </CanvasProvider>
501
+
502
+ // After:
503
+ <CanvasProvider className={customThemeClass}>
504
+ <App />
505
+ </CanvasProvider>
506
+ ```
507
+
508
+ > **Note:** Using a class means you will need to define each property of the palette for full
509
+ > control over theming.
510
+
511
+ ### Step 4: Test Component Rendering
512
+
513
+ Verify that Canvas Kit components (like `PrimaryButton`) correctly use the new CSS variables.
514
+
515
+ ```tsx
516
+ // This should automatically use your CSS variable overrides
517
+ <PrimaryButton>Themed Button</PrimaryButton>
518
+ ```
519
+
520
+ ## Best Practices
521
+
522
+ ### 1. Use Semantic Token Names
523
+
524
+ Use brand tokens instead of base tokens for better maintainability.
525
+
526
+ ```css
527
+ /* ✅ Good - semantic meaning */
528
+ --cnvs-brand-primary-base: var(--cnvs-base-palette-blue-600);
529
+
530
+ /* ❌ Avoid - direct base token usage */
531
+ --cnvs-base-palette-blue-600: blue;
532
+ ```
533
+
534
+ ### 2. Test Accessibility
535
+
536
+ Ensure color combinations meet accessibility standards.
537
+
538
+ ```css
539
+ /* Verify contrast ratios for text/background combinations */
540
+ :root {
541
+ --cnvs-brand-primary-base: var(--cnvs-base-palette-blue-600);
542
+ --cnvs-brand-primary-accent: var(--cnvs-base-palette-neutral-0); /* White text */
543
+ }
544
+ ```
545
+
546
+ ### 3. Avoid Component Level Theming
547
+
548
+ Theming is meant to be done at the app level or root level of the application. Avoid theming at the
549
+ component level.
550
+
551
+ ```tsx
552
+ /* ✅ Good - App level theming */
553
+
554
+ const myCustomTheme = createStyles({
555
+ [brand.primary.base]: base.magenta600
556
+ })
557
+
558
+ <CanvasProvider className={myCustomTheme}>
559
+ <App/>
560
+ </CanvasProvider>
561
+
562
+ /* ❌ Avoid - wrapping components to theme */
563
+
564
+ const myCustomTheme = createStyles({
565
+ [brand.primary.base]: base.magenta600
566
+ })
567
+
568
+ <CanvasProvider className={myCustomTheme}>
569
+ <PrimaryButton>Click Me</PrimaryButton>
570
+ </CanvasProvider>
571
+
572
+ ```
573
+
574
+ ## Component Compatibility
575
+
576
+ All Canvas Kit components in v14 automatically consume CSS variables. No component-level changes are
577
+ required when switching from the theme prop approach to CSS variables.
578
+
579
+ ### Supported Components
580
+
581
+ - ✅ All Button variants (`PrimaryButton`, `SecondaryButton`, etc.)
582
+ - ✅ Form components (`TextInput`, `FormField`, etc.)
583
+ - ✅ Layout components (`Card`, `Modal`, etc.)
584
+ - ✅ Navigation components (`Tabs`, `SidePanel`, etc.)
585
+
586
+ ## Performance Benefits
587
+
588
+ The CSS variable approach provides several performance improvements:
589
+
590
+ - **Reduced Bundle Size**: No JavaScript theme object processing
591
+ - **Better Caching**: CSS variables can be cached by the browser
592
+ - **Faster Rendering**: Native CSS cascade instead of JavaScript calculations
593
+ - **Runtime Efficiency**: No theme context propagation overhead
594
+
595
+ ## Troubleshooting
596
+
597
+ ### Theme Not Applied
598
+
599
+ Ensure CSS variable files are imported in the correct order.
600
+
601
+ > **Note:** You should only import the CSS variables _once_ at the root level of your application.
602
+ > If your application renders within another environment that imports these and sets them, **do
603
+ > not** re import them.
604
+
605
+ ```css
606
+ /* Correct order */
607
+ @import '@workday/canvas-tokens-web/css/base/_variables.css';
608
+ @import '@workday/canvas-tokens-web/css/system/_variables.css';
609
+ @import '@workday/canvas-tokens-web/css/brand/_variables.css';
610
+
611
+ /* Your overrides after imports */
612
+ :root {
613
+ --cnvs-brand-primary-base: var(--cnvs-base-palette-magenta-600);
614
+ }
615
+ ```
616
+
617
+ ### Inconsistent Theming
618
+
619
+ Check for CSS specificity issues.
620
+
621
+ ```css
622
+ /* Ensure your overrides have sufficient specificity */
623
+ :root {
624
+ --cnvs-brand-primary-base: var(--cnvs-base-palette-blue-600) !important;
625
+ }
626
+
627
+ /* Or use more specific selectors */
628
+ .my-app {
629
+ --cnvs-brand-primary-base: var(--cnvs-base-palette-blue-600);
630
+ }
631
+ ```
632
+
633
+ ### Missing Token Values
634
+
635
+ Verify all required CSS token files are imported and token names are correct.
636
+
637
+ ```tsx
638
+ // Check token availability in development
639
+ console.log(brand.primary.base); // Should output CSS variable name
640
+ ```
641
+
642
+ ## Conclusion
643
+
644
+ The migration to CSS variables in Canvas Kit v14 provides a more performant, flexible, and
645
+ maintainable theming solution. By following this guide and best practices, you can successfully
646
+ migrate your applications and take advantage of the improved theming capabilities.
647
+
648
+ For additional support and examples, refer to the Canvas Kit Storybook documentation and the
649
+ `@workday/canvas-tokens` [repository](https://github.com/Workday/canvas-tokens).