@coinbase/cds-mcp-server 8.53.1 → 8.55.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,1762 @@
1
+ ---
2
+ id: v8-migration-guide
3
+ title: v8 Migration Guide
4
+ slug: /guides/v8-migration-guide
5
+ hide_title: true
6
+ ---
7
+
8
+ import { MDXSection } from '@site/src/components/page/MDXSection';
9
+ import { MDXArticle } from '@site/src/components/page/MDXArticle';
10
+ import { ContentHeader } from '@site/src/components/page/ContentHeader';
11
+ import { VStack } from '@coinbase/cds-web/layout';
12
+ import { Tag } from '@coinbase/cds-web/tag/Tag';
13
+ import { Icon } from '@coinbase/cds-web/icons';
14
+
15
+ <VStack gap={5}>
16
+ <ContentHeader title="v8 Migration Guide" />
17
+
18
+ <MDXSection>
19
+ <MDXArticle>
20
+
21
+ ## Introduction
22
+
23
+ CDS v8 is our most feature packed release ever! Including but not limited to:
24
+
25
+ - 🔮 Expanded styling and customization options
26
+ - 🔥 Faster renders and smaller flamegraphs
27
+ - 🦾 Improved accessibility of components and theming
28
+ - 🧩 Simplified and more predictable internal architecture
29
+
30
+ To enable global theming and style customization for all CDS components, some APIs were deprecated or outright deleted. We appreciate the impact this will have on teams adopting CDS v8 and are committed to supporting developers through this upgrade 🏎️
31
+
32
+ If you experience any trouble migrating we're ready to help! Just reach out via Slack.
33
+
34
+ </MDXArticle>
35
+ </MDXSection>
36
+
37
+ <MDXSection>
38
+ <MDXArticle>
39
+
40
+ ## New Packages
41
+
42
+ - `@coinbase/cds-common@8.1.0`
43
+ - `@coinbase/cds-mobile@8.1.0`
44
+ - `@coinbase/cds-mobile-visualization@3.0.0`
45
+ - `@coinbase/cds-web@8.1.0`
46
+ - `@coinbase/cds-web-visualization@3.0.0`
47
+ - `@coinbase/cds-icons@5.0.0`
48
+ - `@coinbase/cds-lottie-files@3.0.0`
49
+
50
+ </MDXArticle>
51
+ </MDXSection>
52
+
53
+ <MDXSection>
54
+ <MDXArticle>
55
+
56
+ ## Migration Script
57
+
58
+ Before diving into the breaking changes, we highly recommend starting with our automated migration script. The `@coinbase/cds-migrator` package handles many of the repetitive transformations automatically, saving you significant time and effort.
59
+
60
+ ### What the Migration Script Automates
61
+
62
+ The migration script handles these transformations automatically:
63
+
64
+ - **Icon migrations**: Active/inactive suffix removal, renamed icons, and active prop additions
65
+ - **Color token updates**: Converts old color names to new semantic tokens
66
+ - **Border radius/width tokens**: Updates string tokens to numeric values and CSS variables
67
+ - **Import path updates**: Fixes outdated import paths throughout your codebase
68
+ - **Component prop changes**: Updates `responsiveConfig` to direct responsive props
69
+ - **Hook migrations**: Updates `useSpectrum`, `useAccessibleForeground`, and other deprecated hooks
70
+
71
+ Look for the <Tag intent="promotional" colorScheme="blue">Migration Script ✓</Tag> tags throughout this guide to identify what's automated.
72
+
73
+ ### Running the Migration Script (Internal to Coinbase)
74
+
75
+ For detailed instructions on running the migration script, refer to the Migrator Guide, reach out via Slack if you need help finding the guide.
76
+
77
+ ### What Requires Manual Migration
78
+
79
+ While the script handles most changes, some breaking changes require manual intervention:
80
+
81
+ - **ThemeProvider setup**: Converting from legacy providers to the new ThemeProvider
82
+ - **Scale/density system removal**: Creating custom dense themes
83
+ - **Custom styling**: Updating CSS-in-JS and styled components
84
+ - **Type definitions**: Updating polymorphic component prop types
85
+ - **Complex component patterns**: Advanced usage that can't be automatically detected
86
+
87
+ </MDXArticle>
88
+ </MDXSection>
89
+
90
+ <MDXSection>
91
+ <MDXArticle>
92
+
93
+ ## Dependency Updates
94
+
95
+ ### Linaria Dependency Requirements
96
+
97
+ **Important:** If you are using `@linaria/core` in your application code, you must properly declare it in your `package.json` dependencies. In CDS v8, we moved `@linaria/core` from `dependencies` to `devDependencies`, which means it will no longer be automatically available to consuming applications.
98
+
99
+ ```json
100
+ {
101
+ "dependencies": {
102
+ "@linaria/core": "^6.0.0"
103
+ }
104
+ }
105
+ ```
106
+
107
+ This is required if your application directly imports from `@linaria/core`:
108
+
109
+ ```tsx
110
+ import { css, cx } from '@linaria/core';
111
+ ```
112
+
113
+ **Alternative for `cx` function:** If you're only using the `cx` function from `@linaria/core`, you can import it directly from `@coinbase/cds-web` instead of adding the dependency:
114
+
115
+ ```tsx
116
+ // ❌ Requires @linaria/core dependency
117
+ import { cx } from '@linaria/core';
118
+
119
+ // ✅ No additional dependency needed
120
+ import { cx } from '@coinbase/cds-web';
121
+ ```
122
+
123
+ </MDXArticle>
124
+ </MDXSection>
125
+
126
+ <MDXSection>
127
+ <MDXArticle>
128
+
129
+ ## 💥 Breaking Change Overview
130
+
131
+ Here's a high-level overview of the major breaking changes in v8:
132
+
133
+ ### 🎨 Theming System Changes
134
+
135
+ - **New ThemeProvider**: Requires `theme` and `activeColorScheme` props (no defaults)
136
+ - **Provider consolidation**: `SpectrumProvider`, `DarkModeProvider`, `LightModeProvider`, and scale providers replaced by single `ThemeProvider`
137
+ - **Spectrum vs Color**: Distinction between spectrum (`"r,g,b"`) and color (CSS values) - prefer color tokens
138
+ - **CSS variables**: Preferred way to access theme values on web for performance
139
+ - **No inheritance**: ThemeProvider no longer auto-inherits from parent providers
140
+ - **Color scheme classes**: ThemeProvider adds `.dark`/`.light` classes to container
141
+ - **Scale/density removed**: No scale system - create custom themes for dense styles
142
+ - **Theme inversion**: `invertSpectrum` → `invertColorScheme`, new `InvertedThemeProvider`
143
+
144
+ ### 🎭 Style System Changes
145
+
146
+ - **Safari support**: Requires Safari 15.4+ for web (CSS layers, `:focus-visible`, `:has()`)
147
+ - **CSS layers**: All CDS styles scoped to `@layer cds` for better specificity control
148
+ - **CSS reset**: New global styles override browser defaults for polymorphic components
149
+ - **Improved polymorphism**: Better type safety for polymorphic components with `as` prop
150
+ - **Elevation simplified**: Streamlined system without `ElevationProvider`/`useElevationStyles`
151
+ - **CSS-in-JS**: Static CSS variables and Linaria-compiled styles instead of runtime calculations
152
+
153
+ ### 🪙 Token Changes
154
+
155
+ - **Color tokens**: Complete redesign with semantic naming:
156
+ - Foreground: `foreground` → `fg`, `primary` → `fgPrimary`
157
+ - Background: `background` → `bg`, `primary` → `bgPrimary`
158
+ - Border: `line` → `bgLine`, `primary` → `bgLinePrimary`
159
+ - **Border radius**: String tokens → numeric (`rounded` → `200`, `roundedFull` → `1000`)
160
+ - **Border width**: String tokens → numeric (`button` → `100`, `focusRing` → `200`)
161
+ - **Import paths**: Many token imports moved to new package locations
162
+
163
+ ### ⭐ Icon Changes
164
+
165
+ - **Active states**: Controlled by `active` prop instead of icon name suffixes (`starFilled` → `<Icon name="star" active />`)
166
+ - **Renamed icons**: Several icons renamed for clarity
167
+ - **Removed props**: `bordered` prop removed from Icon component
168
+ - **Removed components**: `NavigationIcon` and `NavigationIconButton` removed
169
+
170
+ ### 🧩 Component Changes
171
+
172
+ - **Responsive props**: `responsiveConfig` prop removed, use direct responsive props
173
+ - **Media queries**: `deviceBreakpoints`/`deviceMqs` → `breakpoints`/`media`
174
+ - **Removed providers**: `DevicePreferencesProvider`, `BreakpointsProvider`, `FeatureFlagProvider`
175
+ - **Removed components**: Several utility components removed or renamed (`InteractableContent` → `Interactable`)
176
+ - **Import paths**: Component import paths updated to new package structure
177
+
178
+ ### 🔧 Hook & Utility Changes
179
+
180
+ - **useTheme**: Replaces `useSpectrum`, `useScale`, and other theming hooks
181
+ - **Accessibility**: `useAccessibleForeground` → `getAccessibleColor` with new API
182
+ - **Spacing**: `useSpacingScale`/`useSpacingValue` → direct theme token access
183
+ - **Typography**: `useTypographyStyles` → direct theme property access
184
+ - **Scale hooks**: `useScale`, `useScaleConditional` removed (no scale system)
185
+ - **Palette utilities**: `paletteValueToRgbaString`, `usePalette` → theme-based approach
186
+
187
+ ### 📝 Type Changes
188
+
189
+ - **Polymorphic types**: Now require type arguments (`TextProps<'h1'>`, `BoxProps<'div'>`)
190
+ - **Default elements**: `TextDefaultElement`, `BoxDefaultElement` exported for defaults
191
+ - **Removed types**: `HTMLNonHeadingTextTags`, `NoopFn`, `SetState`, `Overflow`, `IconPixelSize`
192
+ - **Updated types**: `GapSpacing` → `ThemeVars.Space`
193
+
194
+ </MDXArticle>
195
+ </MDXSection>
196
+
197
+ <MDXSection>
198
+ <MDXArticle>
199
+
200
+ ## Theming Updates
201
+
202
+ ### The New ThemeProvider
203
+
204
+ In CDS v8, the theming system has been completely redesigned. The new `ThemeProvider` is the single source of truth for all styling and requires both `theme` and `activeColorScheme` props.
205
+
206
+ **Basic Setup:**
207
+
208
+ ```tsx
209
+ import { ThemeProvider } from '@coinbase/cds-web/system/ThemeProvider';
210
+ import { defaultTheme } from '@coinbase/cds-web/themes/defaultTheme';
211
+
212
+ const App = () => {
213
+ return (
214
+ <ThemeProvider theme={defaultTheme} activeColorScheme="light">
215
+ <YourAppContent />
216
+ </ThemeProvider>
217
+ );
218
+ };
219
+ ```
220
+
221
+ **Custom Theme:**
222
+
223
+ ```tsx
224
+ const customTheme = {
225
+ ...defaultTheme,
226
+ lightColor: {
227
+ ...defaultTheme.lightColor,
228
+ bgPrimary: 'rgb(255, 0, 0)',
229
+ },
230
+ space: {
231
+ ...defaultTheme.space,
232
+ 5: 32,
233
+ },
234
+ };
235
+ ```
236
+
237
+ ### The useTheme Hook
238
+
239
+ The `useTheme()` hook provides access to the current theme and active color scheme:
240
+
241
+ ```tsx
242
+ const MyComponent = () => {
243
+ const theme = useTheme();
244
+ console.log(theme.activeColorScheme); // "light" or "dark"
245
+ console.log(theme.spectrum); // Reference to lightSpectrum or darkSpectrum
246
+ console.log(theme.color); // Reference to lightColor or darkColor
247
+ console.log(theme.color.bgPrimary); // "rgb(0,82,255)" or "rgb(87,139,250)"
248
+ console.log(theme.space[2]); // "16px"
249
+ console.log(theme.borderRadius[200]); // "8px"
250
+ console.log(theme.fontSize.display3); // "2.5rem"
251
+ };
252
+ ```
253
+
254
+ **Performance Note:** Whenever possible, use CSS variables on web instead of the `useTheme()` hook to ensure best performance.
255
+
256
+ ### Note about Spectrum vs Color
257
+
258
+ The difference between `theme.spectrum` and `theme.color` is that spectrum values are just `"r,g,b"` strings while color values are valid CSS values. The `theme.color` values have semantic names and you should always prefer to use these values instead of spectrum values when styling UI.
259
+
260
+ ```tsx
261
+ const lightSpectrum = {
262
+ red60: '207,32,47',
263
+ };
264
+
265
+ const theme = {
266
+ lightSpectrum,
267
+ lightColor: {
268
+ bgNegative: `rgb(${lightSpectrum.red60})`,
269
+ },
270
+ };
271
+
272
+ // In components:
273
+ const theme = useTheme();
274
+ console.log(theme.spectrum.red60); // "207,32,47"
275
+ console.log(theme.color.bgNegative); // "rgb(207,32,47)"
276
+ ```
277
+
278
+ ### CSS Variables (Web)
279
+
280
+ On web, `ThemeProvider` creates CSS variables for all theme values:
281
+
282
+ | JS variable | CSS variable |
283
+ | ------------------------- | -------------------- |
284
+ | `theme.color.bgPrimary` | `--color-bgPrimary` |
285
+ | `theme.space[2]` | `--space-2` |
286
+ | `theme.borderRadius[200]` | `--borderRadius-200` |
287
+
288
+ ### Color Scheme Classes (Web)
289
+
290
+ On web, the ThemeProvider adds a `.dark` or `.light` class to its container element depending on the `activeColorScheme`. You can use this class for writing styles specific to the color schemes.
291
+
292
+ ```css
293
+ const myStyles = css`
294
+ .dark {
295
+ background-image: url('http://example.com/dark.png');
296
+ }
297
+
298
+ .light {
299
+ background-image: url('http://example.com/light.png');
300
+ }
301
+ `;
302
+ ```
303
+
304
+ ### ThemeProvider Requirements
305
+
306
+ The ThemeProvider no longer includes default values for the `theme` or `activeColorScheme` props. These props are now required on every ThemeProvider. Any component calling the `useTheme()` hook without a parent ThemeProvider will throw an error, and component styles will be broken.
307
+
308
+ ### ThemeProvider Inheritance
309
+
310
+ The ThemeProvider no longer automatically inherits and merges themes from parent ThemeProviders. However you can manually inherit the theme if you want:
311
+
312
+ ```tsx
313
+ const MyPage = () => {
314
+ const theme = useTheme();
315
+
316
+ const customTheme = {
317
+ ...theme,
318
+ fontFamily: {
319
+ ...theme.fontFamily,
320
+ label1: 'Arial',
321
+ },
322
+ };
323
+
324
+ return (
325
+ <ThemeProvider theme={customTheme} activeColorScheme={theme.activeColorScheme}>
326
+ Customized theming!
327
+ </ThemeProvider>
328
+ );
329
+ };
330
+ ```
331
+
332
+ ### Scale/Density System Removed
333
+
334
+ In CDS v8, the concept of scale/density no longer exists. To achieve dense/xSmall scale styles, you can create a new theme that updates the values of `space`, `fontSize`, `lineHeight`, `controlSize`, `iconSize`, etc.
335
+
336
+ We have an example `coinbaseDenseTheme` you can use to emulate the old dense/xSmall scale styles - [web link](https://github.com/coinbase/cds-staging/blob/master/packages/web/src/themes/coinbaseDenseTheme.ts) and [mobile link](https://github.com/coinbase/cds-staging/blob/master/packages/mobile/src/themes/coinbaseDenseTheme.ts). However you need to copy this theme into your application, it will be deleted from CDS in the next major release.
337
+
338
+ ### Inverting the Theme
339
+
340
+ Some component props like `invertSpectrum` allow inverting a component tree to use the opposite of the current `activeColorScheme`. These props have been renamed to `invertColorScheme`.
341
+
342
+ We have a new InvertedThemeProvider that will do this inversion automatically if the opposite color palette is defined in the theme. If the opposite colors are not defined then the InvertedThemeProvider does nothing.
343
+
344
+ ```tsx
345
+ const MyComponent = ({ invertColorScheme }) => {
346
+ const Wrapper = invertColorScheme ? InvertedThemeProvider : React.Fragment;
347
+ return <Wrapper>Hello world</Wrapper>;
348
+ };
349
+ ```
350
+
351
+ ### Removed Theming APIs
352
+
353
+ The following theming-related APIs have been removed:
354
+
355
+ **Providers:**
356
+
357
+ - `SpectrumProvider` / `RootSpectrumProvider` - [see migration instructions](#migrating-rootspectrumprovider)
358
+ - `DarkModeProvider` / `LightModeProvider` - [see migration instructions](#migrating-darkmodeprovider--lightmodeprovider)
359
+ - `ScaleProvider` / `RootScaleProvider` / `DenseScaleProvider` / `NormalScaleProvider` - [see dense theme migration](#creating-dense-themes)
360
+
361
+ **Hooks:**
362
+
363
+ - `useSpectrum` - Replaced by `useTheme` hook
364
+ - `useScale` / `useScaleConditional` - [see migration instructions](#migrating-scale-related-hooks-no-direct-replacement)
365
+ - `useSpectrumConditional` - [see migration instructions](#migrating-usespectrumconditional)
366
+
367
+ </MDXArticle>
368
+ </MDXSection>
369
+
370
+ <MDXSection>
371
+ <MDXArticle>
372
+
373
+ ## Style Updates
374
+
375
+ ### Safari Web Support
376
+
377
+ CDS v8 for web supports Safari 15.4 and later, released March 14, 2022. We make use of features like CSS layers and selectors like `:focus-visible` and `:has()`.
378
+
379
+ ### CSS Layers
380
+
381
+ All CDS web CSS is now scoped to a [CSS layer](https://developer.mozilla.org/en-US/docs/Web/CSS/@layer) for better specificity control:
382
+
383
+ ```css
384
+ @layer cds {
385
+ .hello-world {
386
+ color: red;
387
+ }
388
+ }
389
+ ```
390
+
391
+ This causes CDS CSS to have lower style specificity than styles that are not on a CSS layer - which makes it easy to ensure your custom styles always overwrite CDS. This solves problems with non-deterministic styles based on stylesheet load order.
392
+
393
+ ### New Web Global Styles
394
+
395
+ CDS web global styles now include a CSS reset which override the browser default styles for some elements. This ensures that polymorphic components render correctly, regardless of their HTML element. See the [full style reset here](https://github.com/coinbase/cds-staging/blob/master/packages/web/src/styles/global.ts).
396
+
397
+ ### Improved Polymorphism
398
+
399
+ Many web components are now fully polymorphic with strong type checking:
400
+
401
+ ```tsx
402
+ // Without the `as` prop, href throws a type error
403
+ <Button href="example.com" />
404
+ // With the `as` prop, all native anchor props are valid
405
+ <Button as="a" href="example.com" />
406
+ ```
407
+
408
+ ### Elevation Changes
409
+
410
+ CDS v8 introduces a simplified elevation system that replaces the complex context-based approach with streamlined implementations for both web and mobile platforms. The elevation prop continues to support the same levels (0, 1, 2), but the underlying implementation has been significantly simplified for better performance and developer experience.
411
+
412
+ In CDS web, the new elevation system uses static CSS variables and Linaria-compiled styles instead of runtime calculations. v8 removes the `ElevationProvider` context and `useElevationStyles` hook in favor of direct component props. This change eliminates the need for context providers and custom hooks while providing more consistent visual results across light and dark themes.
413
+
414
+ In CDS mobile, the complex `ElevationConfigsProvider` and `createElevationConfigForSpectrum` system has been replaced with direct theme-based styling through the `getElevationStyles` function, removing the need for context providers and wrapper components.
415
+
416
+ ### Removed Style APIs
417
+
418
+ The following style-related APIs have been removed:
419
+
420
+ **Providers:**
421
+
422
+ - `ElevationConfigsProvider` - [see migration instructions](#migrating-elevationconfigsprovider)
423
+
424
+ **Hooks:**
425
+
426
+ - `useTypographyStyles` - [see migration instructions](#migrating-usetypographystyles)
427
+ - `useThemeProviderStyles` - [see migration instructions](#migrating-usethemeproviderstyles)
428
+ - `useSpacingStyles` - [see migration instructions](#migrating-usespacingstyles)
429
+ - `useSpacingScale` / `useSpacingValue` - [see migration instructions](#migrating-usespacingscale--usespacingvalue)
430
+
431
+ ### New Style Tokens
432
+
433
+ CDS v8 introduces many new themeable style tokens. The value of these tokens is configured in the ThemeProvider.
434
+
435
+ **Example: Using New Color Tokens**
436
+
437
+ ```tsx
438
+ // ❌ Before (v7)
439
+ <Box background="primary" color="primaryForeground">
440
+ <Text color="secondary">Hello</Text>
441
+ </Box>
442
+
443
+ // ✅ After (v8)
444
+ <Box background="bgPrimary" color="fgInverse">
445
+ <Text color="fgMuted">Hello</Text>
446
+ </Box>
447
+ ```
448
+
449
+ ### CSS Variables in Styled Components
450
+
451
+ ```tsx
452
+ // ❌ Before (v7)
453
+ const StyledCard = styled.div`
454
+ background: ${palette.background};
455
+ border: 1px solid ${palette.line};
456
+ padding: ${spacing[3]};
457
+ `;
458
+
459
+ // ✅ After (v8)
460
+ const StyledCard = styled.div`
461
+ background: var(--color-bg);
462
+ border: var(--borderWidth-100) solid var(--color-bgLine);
463
+ padding: var(--space-3);
464
+ `;
465
+ ```
466
+
467
+ ### Mobile StyleSheet Updates
468
+
469
+ ```tsx
470
+ // ❌ Before (v7)
471
+ import { borderRadius, colors } from '@coinbase/cds-mobile/tokens';
472
+
473
+ const styles = StyleSheet.create({
474
+ card: {
475
+ backgroundColor: colors.background,
476
+ borderRadius: borderRadius.rounded,
477
+ },
478
+ });
479
+
480
+ // ✅ After (v8)
481
+ import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
482
+
483
+ const MyComponent = () => {
484
+ const theme = useTheme();
485
+
486
+ const styles = StyleSheet.create({
487
+ card: {
488
+ backgroundColor: theme.color.bg,
489
+ borderRadius: theme.borderRadius[200],
490
+ },
491
+ });
492
+
493
+ return <View style={styles.card} />;
494
+ };
495
+ ```
496
+
497
+ </MDXArticle>
498
+ </MDXSection>
499
+
500
+ <MDXSection>
501
+ <MDXArticle>
502
+
503
+ ## Token Updates
504
+
505
+ ### Foreground Color Token Mapping
506
+
507
+ | v7 Token | v8 Token |
508
+ | --------------------- | ------------- |
509
+ | `foreground` | `fg` |
510
+ | `foregroundMuted` | `fgMuted` |
511
+ | `primary` | `fgPrimary` |
512
+ | `primaryForeground` | `fgInverse` |
513
+ | `secondary` | `bgSecondary` |
514
+ | `secondaryForeground` | `fg` |
515
+ | `positive` | `fgPositive` |
516
+ | `positiveForeground` | `fgInverse` |
517
+ | `negative` | `fgNegative` |
518
+ | `negativeForeground` | `fgInverse` |
519
+ | `warning` | `bgWarning` |
520
+ | `warningForeground` | `fgWarning` |
521
+
522
+ ### Background Color Token Mapping
523
+
524
+ | v7 Token | v8 Token |
525
+ | --------------------- | ---------------- |
526
+ | `background` | `bg` |
527
+ | `backgroundAlternate` | `bgAlternate` |
528
+ | `backgroundOverlay` | `bgOverlay` |
529
+ | `backgroundInverse` | `bgInverse` |
530
+ | `primary` | `bgPrimary` |
531
+ | `secondary` | `bgSecondary` |
532
+ | `positive` | `bgPositive` |
533
+ | `negative` | `bgNegative` |
534
+ | `warning` | `bgWarning` |
535
+ | `primaryWash` | `bgPrimaryWash` |
536
+ | `negativeWash` | `bgNegativeWash` |
537
+ | `transparent` | `transparent` |
538
+
539
+ ### Border Color Token Mapping
540
+
541
+ | v7 Token | v8 Token |
542
+ | ------------------- | --------------------- |
543
+ | `primary` | `bgLinePrimary` |
544
+ | `primaryWash` | `bgLinePrimarySubtle` |
545
+ | `secondary` | `bgLine` |
546
+ | `positive` | `bgPositive` |
547
+ | `negative` | `bgNegative` |
548
+ | `line` | `bgLine` |
549
+ | `lineHeavy` | `bgLineHeavy` |
550
+ | `transparent` | `transparent` |
551
+ | `warning` | `bgWarning` |
552
+ | `warningForeground` | `fgWarning` |
553
+
554
+ ### Border Radius Token Mapping
555
+
556
+ | v7 Token | v8 Token |
557
+ | --------------- | -------- |
558
+ | `roundedNone` | `0` |
559
+ | `roundedSmall` | `100` |
560
+ | `rounded` | `200` |
561
+ | `roundedMedium` | `300` |
562
+ | `roundedLarge` | `400` |
563
+ | `roundedXLarge` | `500` |
564
+ | `roundedFull` | `1000` |
565
+
566
+ ### Border Width Token Mapping
567
+
568
+ | v7 Token | v8 Token |
569
+ | ----------- | -------- |
570
+ | `none` | `0` |
571
+ | `button` | `100` |
572
+ | `card` | `100` |
573
+ | `checkbox` | `200` |
574
+ | `radio` | `200` |
575
+ | `sparkline` | `200` |
576
+ | `focusRing` | `200` |
577
+ | `input` | `100` |
578
+
579
+ ### Removed Token APIs
580
+
581
+ The following token-related APIs have been removed:
582
+
583
+ **Functions:**
584
+
585
+ - `paletteValueToRgbaString` - [see migration instructions](#migrating-color-palette-functions)
586
+ - `paletteAliasToRgbaString` - [see migration instructions](#migrating-color-palette-functions)
587
+
588
+ **Hooks:**
589
+
590
+ - `usePalette` - [see migration instructions](#migrating-color-palette-functions)
591
+ - `usePaletteConfig` - [see migration instructions](#migrating-color-palette-functions)
592
+
593
+ **Constants:**
594
+
595
+ - `defaultPalette` - [see migration instructions](#migrating-color-palette-functions)
596
+
597
+ </MDXArticle>
598
+ </MDXSection>
599
+
600
+ <MDXSection>
601
+ <MDXArticle>
602
+
603
+ ## Icon Updates
604
+
605
+ ### Renamed Icons
606
+
607
+ <Tag intent="promotional">Migration Script ✓</Tag>
608
+
609
+ The following icons have been renamed:
610
+
611
+ - `visibleInactive` → `invisible`
612
+ - `followInactive` → `followAdd`
613
+ - `visibleFilled` → `visible`
614
+ - `rocketInactive` → `noRocket`
615
+ - `followActive` → `following`
616
+
617
+ ### Active State Changes
618
+
619
+ <Tag intent="promotional">Migration Script ✓</Tag>
620
+
621
+ For certain UI icons whose names end with Active or Inactive suffixes, their active state is now controlled by a boolean `active` prop -- see the complete [migration instructions](#icon-components-with-active-states).
622
+
623
+ **Affected icons**: See the complete [UI Icon Exceptions list](#icon-components-with-active-states) in the migration instructions.
624
+
625
+ **Affected components**: `Icon`, `CellMedia`, `IconButton`, `Button`, `Banner`.
626
+
627
+ ### Removed Icon APIs
628
+
629
+ The following icon-related APIs have been removed:
630
+
631
+ **Props:**
632
+
633
+ - `bordered` prop from `Icon` component - [see migration instructions](#migrating-bordered-icon-prop)
634
+
635
+ **Components:**
636
+
637
+ - `NavigationIcon` & `NavigationIconButton` - Use standard `Icon` and `IconButton` instead - [see migration instructions](#migrating-navigationiconnavigationiconbutton)
638
+
639
+ </MDXArticle>
640
+ </MDXSection>
641
+
642
+ <MDXSection>
643
+ <MDXArticle>
644
+
645
+ ## Component Updates
646
+
647
+ ### Responsive Props
648
+
649
+ <Tag intent="promotional">Migration Script ✓</Tag>
650
+
651
+ The `responsiveConfig` prop has been removed. Pass responsive values directly to each prop:
652
+
653
+ ```tsx
654
+ // ❌ Before
655
+ const responsiveConfig = { desktop: { gap: 2 }, tablet: { gap: 3 } };
656
+ <Box responsiveConfig={responsiveConfig}>Content</Box>
657
+
658
+ // ✅ After
659
+ <Box gap={{ desktop: 2, tablet: 3 }}>Content</Box>
660
+ ```
661
+
662
+ ### Breakpoints & Media Queries
663
+
664
+ Import paths and values have been updated:
665
+
666
+ ```tsx
667
+ // ❌ Before (v7)
668
+ import { deviceBreakpoints, deviceMqs } from '@coinbase/cds-web/layout/breakpoints';
669
+
670
+ // ✅ After (v8)
671
+ import { breakpoints, media } from '@coinbase/cds-web/styles/media';
672
+ ```
673
+
674
+ ### Removed Component APIs
675
+
676
+ The following component-related APIs have been removed:
677
+
678
+ **Providers:**
679
+
680
+ - `DevicePreferencesProvider` - [see migration instructions](#migrating-devicepreferencesprovider)
681
+ - `BreakpointsProvider` - [see migration instructions](#migrating-breakpointsprovider)
682
+ - `FeatureFlagProvider` - [see migration instructions](#migrating-featureflagprovider)
683
+
684
+ **Components:**
685
+
686
+ - `InteractableContent` - Renamed to `Interactable` - [see migration instructions](#migrating-interactablecontent)
687
+
688
+ **Hooks:**
689
+
690
+ - `useMergedRef` - [see migration instructions](#migrating-usemergedref)
691
+ - `useToggler` - [see migration instructions](#migrating-usetoggler)
692
+ - `useMediaQuery` / `useDeviceColorScheme` - Use theme-based approach instead
693
+ - `useIconSize` / `useAvatarSize` - [see migration instructions](#migrating-scale-related-hooks-no-direct-replacement)
694
+ - `useInteractableHeight` - [see migration instructions](#migrating-scale-related-hooks-no-direct-replacement)
695
+
696
+ **Utilities:**
697
+
698
+ - `overflowClassName` - Replace with inline CSS: `{ overflow: auto; text-overflow: unset; white-space: normal; }` - [see migration instructions](#migrating-overflowclassname)
699
+
700
+ </MDXArticle>
701
+ </MDXSection>
702
+
703
+ <MDXSection>
704
+ <MDXArticle>
705
+
706
+ ## Type Updates
707
+
708
+ ### Polymorphic Component Props
709
+
710
+ All polymorphic component prop types now require a type argument:
711
+
712
+ ```tsx
713
+ // ❌ Before (v7)
714
+ interface MyComponentProps {
715
+ textProps: TextProps;
716
+ boxProps: BoxProps;
717
+ }
718
+
719
+ // ✅ After (v8)
720
+ import { TextProps, TextDefaultElement } from '@coinbase/cds-web/typography/Text';
721
+ import { BoxProps, BoxDefaultElement } from '@coinbase/cds-web/layout/Box';
722
+
723
+ interface MyComponentProps {
724
+ textProps: TextProps<TextDefaultElement>;
725
+ boxProps: BoxProps<BoxDefaultElement>;
726
+ }
727
+
728
+ // Or with specific element types
729
+ interface MySpecificComponentProps {
730
+ headingProps: TextProps<'h1'>;
731
+ linkProps: BoxProps<'a'>;
732
+ }
733
+ ```
734
+
735
+ ### Removed Type APIs
736
+
737
+ The following type-related APIs have been removed:
738
+
739
+ **Types:**
740
+
741
+ - `HTMLNonHeadingTextTags` - Define locally if needed - [see migration instructions](#migrating-removed-types)
742
+ - `LinkTypography` - Replace with `LinkProps<LinkDefaultElement>['font']`
743
+ - `BoxElement` - Use `BoxDefaultElement` or define as `keyof JSX.IntrinsicElements`
744
+ - `Overflow` - Define locally as `{ overflow?: 'visible' | 'hidden' | 'scroll' | 'auto' | 'clip' }` - [see migration instructions](#migrating-removed-types)
745
+
746
+ **Constants:**
747
+
748
+ - `paletteForegrounds`, `paletteBackgrounds`, `paletteBorders`
749
+
750
+ </MDXArticle>
751
+ </MDXSection>
752
+
753
+ <MDXSection>
754
+ <MDXArticle>
755
+
756
+ ## FAQ
757
+
758
+ ### Why upgrade to v8?
759
+
760
+ CDS v8 brings faster performance, full theming and customization, powerful new APIs, and improved accessibility. It also includes React 19 support, a rebuilt docs site, and an MCP server to streamline development.
761
+
762
+ ### What new features are included?
763
+
764
+ This release includes:
765
+
766
+ - Theming and customization
767
+ - Drastically improved performance
768
+ - CDS MCP Server
769
+ - Powerful new APIs
770
+ - All new docs site
771
+ - React 19 support
772
+ - 5 new components
773
+
774
+ ### Are migration scripts available?
775
+
776
+ Yes! We provide the `@coinbase/cds-migrator` package to assist with automated migration. For detailed instructions, refer to the [Migrator Guide](https://github.com/coinbase/cds-staging/blob/master/packages/migrator/README.md).
777
+
778
+ </MDXArticle>
779
+ </MDXSection>
780
+
781
+ <MDXSection>
782
+ <MDXArticle>
783
+
784
+ ## Appendix: Detailed Migration Instructions
785
+
786
+ This section provides step-by-step instructions for migrating specific APIs and components that have been removed or updated. Each section corresponds to the breaking changes outlined above.
787
+
788
+ **Note:** Code examples may show platform-specific import paths (e.g., `@coinbase/cds-web` or `@coinbase/cds-mobile`). Adjust the import paths based on your target platform.
789
+
790
+ ### Theming Migration Instructions
791
+
792
+ _See [Theming Updates](#theming-updates) for overview_
793
+
794
+ #### Migrating DevicePreferencesProvider
795
+
796
+ **On Web:**
797
+
798
+ ```tsx
799
+ // ❌ Before (v7)
800
+ import { DevicePreferencesProvider } from '@coinbase/cds-web/system';
801
+
802
+ const App = () => (
803
+ <DevicePreferencesProvider>
804
+ <YourAppContent />
805
+ </DevicePreferencesProvider>
806
+ );
807
+
808
+ // ✅ After (v8)
809
+ import { ThemeProvider } from '@coinbase/cds-web/system/ThemeProvider';
810
+ import { defaultTheme } from '@coinbase/cds-web/themes/defaultTheme';
811
+ import { MediaQueryProvider } from '@coinbase/cds-web/system/MediaQueryProvider';
812
+ import { useMediaQuery } from '@coinbase/cds-web/hooks/useMediaQuery';
813
+
814
+ const App = () => {
815
+ const prefersDark = useMediaQuery('(prefers-color-scheme: dark)');
816
+ const activeColorScheme = prefersDark ? 'dark' : 'light';
817
+
818
+ return (
819
+ <MediaQueryProvider>
820
+ <ThemeProvider theme={defaultTheme} activeColorScheme={activeColorScheme}>
821
+ <YourAppContent />
822
+ </ThemeProvider>
823
+ </MediaQueryProvider>
824
+ );
825
+ };
826
+ ```
827
+
828
+ **On Mobile:**
829
+
830
+ ```tsx
831
+ // ❌ Before (v7)
832
+ import { DevicePreferencesProvider } from '@coinbase/cds-mobile/system';
833
+
834
+ // ✅ After (v8)
835
+ import { ThemeProvider } from '@coinbase/cds-mobile/system/ThemeProvider';
836
+ import { defaultTheme } from '@coinbase/cds-mobile/themes/defaultTheme';
837
+ import { useDeviceColorScheme } from '@coinbase/cds-mobile/hooks/useDeviceColorScheme';
838
+
839
+ const App = () => {
840
+ const deviceColorScheme = useDeviceColorScheme();
841
+ const [userPreference, setUserPreference] = useState<'system' | 'light' | 'dark'>('system');
842
+
843
+ const activeColorScheme = userPreference === 'system' ? deviceColorScheme : userPreference;
844
+
845
+ return (
846
+ <ThemeProvider theme={defaultTheme} activeColorScheme={activeColorScheme}>
847
+ <YourApp />
848
+ {/* Somewhere in your settings */}
849
+ <Button onPress={() => setUserPreference('dark')}>Dark Mode</Button>
850
+ <Button onPress={() => setUserPreference('light')}>Light Mode</Button>
851
+ <Button onPress={() => setUserPreference('system')}>Follow System</Button>
852
+ </ThemeProvider>
853
+ );
854
+ };
855
+ ```
856
+
857
+ #### Migrating BreakpointsProvider
858
+
859
+ **Steps:**
860
+
861
+ 1. Remove the `BreakpointsProvider` import
862
+ 2. Add `import { MediaQueryProvider } from '@coinbase/cds-web/system/MediaQueryProvider'`
863
+ 3. Replace `BreakpointsProvider` with `MediaQueryProvider`
864
+ 4. Add the `defaultValues` prop if needed
865
+
866
+ ```tsx
867
+ // ❌ Before (v7)
868
+ import { BreakpointsProvider } from '@coinbase/cds-web/system/BreakpointsProvider';
869
+
870
+ // ✅ After (v8)
871
+ import { MediaQueryProvider } from '@coinbase/cds-web/system/MediaQueryProvider';
872
+
873
+ const App = () => (
874
+ <MediaQueryProvider>
875
+ <YourApp />
876
+ </MediaQueryProvider>
877
+ );
878
+ ```
879
+
880
+ #### Migrating RootSpectrumProvider
881
+
882
+ **Steps:**
883
+
884
+ 1. Replace `RootSpectrumProvider` with `ThemeProvider`
885
+ 2. Add your own device color scheme detection logic using `useDeviceColorScheme()` hook
886
+ 3. Implement user preference state management
887
+
888
+ ```tsx
889
+ // ❌ Before (v7)
890
+ import { RootSpectrumProvider } from '@coinbase/cds-mobile/system';
891
+
892
+ // ✅ After (v8) - Manual override with state management
893
+ import { ThemeProvider } from '@coinbase/cds-mobile/system/ThemeProvider';
894
+ import { defaultTheme } from '@coinbase/cds-mobile/themes/defaultTheme';
895
+ import { useDeviceColorScheme } from '@coinbase/cds-mobile/hooks/useDeviceColorScheme';
896
+
897
+ const App = () => {
898
+ const deviceColorScheme = useDeviceColorScheme();
899
+ const [userPreference, setUserPreference] = useState<'system' | 'light' | 'dark'>('system');
900
+
901
+ const activeColorScheme = userPreference === 'system' ? deviceColorScheme : userPreference;
902
+
903
+ return (
904
+ <ThemeProvider theme={defaultTheme} activeColorScheme={activeColorScheme}>
905
+ <YourApp />
906
+ {/* Somewhere in your settings */}
907
+ <Button onPress={() => setUserPreference('dark')}>Dark Mode</Button>
908
+ <Button onPress={() => setUserPreference('light')}>Light Mode</Button>
909
+ <Button onPress={() => setUserPreference('system')}>Follow System</Button>
910
+ </ThemeProvider>
911
+ );
912
+ };
913
+ ```
914
+
915
+ #### Migrating DarkModeProvider / LightModeProvider
916
+
917
+ **Steps:**
918
+
919
+ 1. Remove `DarkModeProvider` and `LightModeProvider` imports
920
+ 2. Replace with `ThemeProvider` that has `activeColorScheme` set to `"dark"` or `"light"`
921
+
922
+ ```tsx
923
+ // ❌ Before (v7)
924
+ import { DarkModeProvider, LightModeProvider } from '@coinbase/cds-mobile/system';
925
+
926
+ <DarkModeProvider>
927
+ <YourApp />
928
+ </DarkModeProvider>
929
+
930
+ <LightModeProvider>
931
+ <YourApp />
932
+ </LightModeProvider>
933
+
934
+ // ✅ After (v8)
935
+ import { ThemeProvider } from '@coinbase/cds-mobile/system/ThemeProvider';
936
+ import { defaultTheme } from '@coinbase/cds-mobile/themes/defaultTheme';
937
+
938
+ <ThemeProvider theme={defaultTheme} activeColorScheme="dark">
939
+ <YourApp />
940
+ </ThemeProvider>
941
+
942
+ <ThemeProvider theme={defaultTheme} activeColorScheme="light">
943
+ <YourApp />
944
+ </ThemeProvider>
945
+ ```
946
+
947
+ #### Migrating FeatureFlagProvider
948
+
949
+ **Steps:**
950
+
951
+ 1. Simply remove `FeatureFlagProvider` from your component tree
952
+ 2. The benefits it provided are now automatic in v8
953
+
954
+ ```tsx
955
+ // ❌ Before (v7)
956
+ import { FeatureFlagProvider } from '@coinbase/cds-web/system';
957
+
958
+ <FeatureFlagProvider>
959
+ <YourApp />
960
+ </FeatureFlagProvider>
961
+
962
+ // ✅ After (v8)
963
+ // Simply remove the provider - modern behaviors like CSS gap are now default
964
+ <YourApp />
965
+ ```
966
+
967
+ **What was automated:**
968
+
969
+ - CSS gap support
970
+ - Fabric support
971
+ - Other modern behaviors that required opt-in
972
+
973
+ #### Migrating ElevationConfigsProvider
974
+
975
+ **Steps:**
976
+
977
+ 1. Remove `ElevationConfigsProvider` from your component tree
978
+ 2. The elevation system has been simplified and no longer needs this provider
979
+
980
+ ```tsx
981
+ // ❌ Before (v7)
982
+ import { ElevationConfigsProvider } from '@coinbase/cds-mobile/system';
983
+
984
+ <ElevationConfigsProvider>
985
+ <YourApp />
986
+ </ElevationConfigsProvider>
987
+
988
+ // ✅ After (v8)
989
+ // Simply remove the provider - elevation is now handled directly by components
990
+ <YourApp />
991
+ ```
992
+
993
+ #### Creating Dense Themes
994
+
995
+ _Related to the scale system removal mentioned in [Theming Updates](#theming-updates)_
996
+
997
+ **Steps:**
998
+
999
+ 1. Copy the example `coinbaseDenseTheme` from CDS
1000
+ 2. Create theme switching logic
1001
+
1002
+ **Example:**
1003
+
1004
+ ```tsx
1005
+ import { ThemeProvider } from '@coinbase/cds-web/system/ThemeProvider';
1006
+ import { coinbaseDenseTheme } from '@coinbase/cds-web/themes/coinbaseDenseTheme';
1007
+ import { coinbaseTheme } from '@coinbase/cds-web/themes/coinbaseTheme';
1008
+
1009
+ // override the dense theme with your own values if needed
1010
+ const myDenseTheme = {
1011
+ ...coinbaseDenseTheme,
1012
+ id: 'dense-theme',
1013
+ space: {
1014
+ '0': 0,
1015
+ '0.25': 2,
1016
+ '0.5': 4,
1017
+ '0.75': 6,
1018
+ '1': 8,
1019
+ '1.5': 10,
1020
+ '2': 12, // vs 16 in default
1021
+ '3': 16, // vs 24 in default
1022
+ '4': 20, // vs 32 in default
1023
+ '5': 24, // vs 40 in default
1024
+ // ... other smaller values
1025
+ },
1026
+ fontSize: {
1027
+ headline: 14, // vs 16 in default
1028
+ body: 14, // vs 16 in default
1029
+ // ... other smaller font sizes
1030
+ },
1031
+ // ... other dense tokens
1032
+ };
1033
+
1034
+ const App = ({ activeColorScheme }) => {
1035
+ const [isDense, setIsDense] = React.useState(false);
1036
+ const theme = isDense ? myDenseTheme : coinbaseTheme;
1037
+
1038
+ return (
1039
+ <ThemeProvider theme={theme} activeColorScheme={activeColorScheme}>
1040
+ <Button onClick={() => setIsDense((d) => !d)}>Toggle Density</Button>
1041
+ <YourApp />
1042
+ </ThemeProvider>
1043
+ );
1044
+ };
1045
+ ```
1046
+
1047
+ ### Style Migration Instructions
1048
+
1049
+ _See [Style Updates](#style-updates) for overview_
1050
+
1051
+ #### Migrating useThemeProviderStyles
1052
+
1053
+ **Steps:**
1054
+
1055
+ 1. Update the import path: `import { useThemeProviderStyles } from '@coinbase/cds-web/system/ThemeProvider';`
1056
+ 2. Remove `className` references (no longer returned)
1057
+ 3. Update hook usage
1058
+
1059
+ ```tsx
1060
+ // ❌ Before (v7)
1061
+ const { className, style } = useThemeProviderStyles();
1062
+
1063
+ // ✅ After (v8)
1064
+ import { useThemeProviderStyles } from '@coinbase/cds-web/system/ThemeProvider';
1065
+ const style = useThemeProviderStyles();
1066
+ ```
1067
+
1068
+ #### Migrating useTypographyStyles
1069
+
1070
+ _Related to new style tokens mentioned in [Style Updates](#style-updates)_
1071
+
1072
+ **On Web:**
1073
+
1074
+ ```tsx
1075
+ // ❌ Before (v7)
1076
+ const styles = useTypographyStyles('body');
1077
+
1078
+ // ✅ After (v8)
1079
+ const styles = {
1080
+ fontFamily: 'var(--fontFamily-text)',
1081
+ fontSize: 'var(--fontSize-body)',
1082
+ lineHeight: 'var(--lineHeight-body)',
1083
+ };
1084
+
1085
+ // For display typography:
1086
+ const displayStyles = {
1087
+ fontFamily: 'var(--fontFamily-display1)',
1088
+ fontSize: 'var(--fontSize-display1)',
1089
+ fontWeight: 'var(--fontWeight-display1)',
1090
+ lineHeight: 'var(--lineHeight-display1)',
1091
+ };
1092
+ ```
1093
+
1094
+ **On Mobile:**
1095
+
1096
+ ```tsx
1097
+ // ❌ Before (v7)
1098
+ const styles = useTypographyStyles('headline');
1099
+
1100
+ // ✅ After (v8)
1101
+ const theme = useTheme();
1102
+ const headlineStyles = useMemo(
1103
+ () => ({
1104
+ fontSize: theme.fontSize.headline,
1105
+ lineHeight: theme.lineHeight.headline,
1106
+ fontWeight: theme.fontWeight.headline,
1107
+ fontFamily: theme.fontFamily.headline,
1108
+ }),
1109
+ [theme],
1110
+ );
1111
+
1112
+ // Or access individual values directly
1113
+ const bodyLineHeight = theme.lineHeight.body;
1114
+ ```
1115
+
1116
+ #### Migrating useSpacingStyles
1117
+
1118
+ **Steps:**
1119
+
1120
+ 1. Remove the import of `useSpacingStyles`
1121
+ 2. Replace with native padding/margin style properties
1122
+
1123
+ ```tsx
1124
+ // ❌ Before (v7)
1125
+ const spacingStyles = useSpacingStyles();
1126
+
1127
+ // ✅ After (v8)
1128
+ // web
1129
+ const styles = css`
1130
+ padding: var(--space-1)
1131
+ margin: calc(-1 * var(--space-1)))
1132
+ `;
1133
+
1134
+ // mobile
1135
+ const theme = useTheme();
1136
+ const styles = {
1137
+ padding: theme.space[1],
1138
+ margin: -theme.space[1],
1139
+ };
1140
+ ```
1141
+
1142
+ ### Token Migration Instructions
1143
+
1144
+ _See [Token Updates](#token-updates) for overview and mapping tables_
1145
+
1146
+ #### Migrating useSpacingScale / useSpacingValue
1147
+
1148
+ **On Web:**
1149
+
1150
+ ```tsx
1151
+ // ❌ Before (v7)
1152
+ import { useSpacingValue } from '@coinbase/cds-web/hooks/useSpacingValue';
1153
+ const paddingValue = useSpacingValue(3);
1154
+
1155
+ // ✅ After (v8) - CSS Variables
1156
+ const paddingValue = 'var(--space-3)';
1157
+
1158
+ // Or direct calculation
1159
+ const paddingValue = 3 * 8; // 24px
1160
+ ```
1161
+
1162
+ **On Mobile:**
1163
+
1164
+ ```tsx
1165
+ // ❌ Before (v7)
1166
+ import { useSpacingValue } from '@coinbase/cds-mobile/hooks/useSpacingValue';
1167
+ const spacing = useSpacingValue(1);
1168
+
1169
+ // ✅ After (v8)
1170
+ import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
1171
+ const theme = useTheme();
1172
+ const spacing = theme.space[1];
1173
+ ```
1174
+
1175
+ #### Migrating borderRadius Tokens
1176
+
1177
+ _Refer to [Border Radius Token Mapping](#token-updates) table_
1178
+
1179
+ **Steps:**
1180
+
1181
+ 1. Remove the import of `borderRadius`
1182
+ 2. Replace usage with CSS variables or theme tokens
1183
+
1184
+ ```tsx
1185
+ // ❌ Before (v7)
1186
+ import { borderRadius } from '@coinbase/cds-common/tokens/borderRadius';
1187
+ const radius = borderRadius.rounded;
1188
+
1189
+ // ✅ After (v8) - CSS Variables
1190
+ const radius = 'var(--borderRadius-200)';
1191
+
1192
+ // Or using useTheme Hook:
1193
+ const theme = useTheme();
1194
+ const radius = theme.borderRadius[200];
1195
+ ```
1196
+
1197
+ #### Migrating borderWidth Tokens
1198
+
1199
+ _Refer to [Border Width Token Mapping](#token-updates) table_
1200
+
1201
+ **Steps:**
1202
+
1203
+ 1. Remove the import of `borderWidth`
1204
+ 2. Import `useTheme` if needed
1205
+ 3. Replace with theme tokens
1206
+
1207
+ ```tsx
1208
+ // ❌ Before (v7)
1209
+ import { borderWidth } from '@coinbase/cds-common/tokens/borderWidth';
1210
+ const width = borderWidth.button;
1211
+
1212
+ // ✅ After (v8)
1213
+ import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
1214
+ const theme = useTheme();
1215
+ const width = theme.borderWidth[100];
1216
+ ```
1217
+
1218
+ #### Migrating Color Palette Functions
1219
+
1220
+ _Refer to [Color Token Mapping](#token-updates) table_
1221
+
1222
+ **paletteValueToRgbaString:**
1223
+
1224
+ ```tsx
1225
+ // ❌ Before (v7)
1226
+ import { paletteValueToRgbaString } from '@coinbase/cds-common/palette/paletteValueToRgbaString';
1227
+ const color = paletteValueToRgbaString('green0', activeColorScheme);
1228
+
1229
+ // ✅ After (v8)
1230
+ import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
1231
+ const theme = useTheme();
1232
+ const color = `rgba(${theme.spectrum.green0}, 0.1)`;
1233
+ ```
1234
+
1235
+ **paletteValueToHex:**
1236
+
1237
+ ```tsx
1238
+ // ❌ Before (v7)
1239
+ import { paletteValueToHex } from '@coinbase/cds-common/palette/paletteValueToHex';
1240
+ const color = paletteValueToHex('gray60', activeColorScheme);
1241
+
1242
+ // ✅ After (v8)
1243
+ import { useTheme } from '@coinbase/cds-web/hooks/useTheme';
1244
+ const theme = useTheme();
1245
+ const color = theme.spectrum.gray60;
1246
+ ```
1247
+
1248
+ **paletteAliasToRgbaString:**
1249
+
1250
+ ```tsx
1251
+ // ❌ Before (v7)
1252
+ import { paletteAliasToRgbaString } from '@coinbase/cds-common/palette/paletteAlias';
1253
+ const color = paletteAliasToRgbaString('primary', activeColorScheme);
1254
+
1255
+ // ✅ After (v8)
1256
+ import { useTheme } from '@coinbase/cds-web/hooks/useTheme';
1257
+ const theme = useTheme();
1258
+ const color = theme.color.fgPrimary;
1259
+ ```
1260
+
1261
+ **usePalette:**
1262
+
1263
+ ```tsx
1264
+ // ❌ Before (v7)
1265
+ import { usePalette } from '@coinbase/cds-web/hooks/usePalette';
1266
+ const palette = usePalette();
1267
+ const color = palette.foregroundMuted;
1268
+
1269
+ // ✅ After (v8)
1270
+ import { useTheme } from '@coinbase/cds-web/hooks/useTheme';
1271
+ const theme = useTheme();
1272
+ const color = theme.color.fgMuted;
1273
+ ```
1274
+
1275
+ **Palette Constants (paletteForegrounds, paletteBackgrounds, paletteBorders):**
1276
+
1277
+ ```tsx
1278
+ // ❌ Before (v7)
1279
+ import {
1280
+ paletteBackgrounds,
1281
+ paletteForegrounds,
1282
+ paletteBorders,
1283
+ } from '@coinbase/cds-common/palette/constants';
1284
+ const bgColor = paletteBackgrounds[1];
1285
+ const textColor = paletteForegrounds[0];
1286
+ const borderColor = paletteBorders[2];
1287
+
1288
+ // ✅ After (v8)
1289
+ // Use specific color token names instead
1290
+ const bgColor = 'bgAlternate';
1291
+ const textColor = 'fg';
1292
+ const borderColor = 'bgLine';
1293
+ ```
1294
+
1295
+ **Steps:**
1296
+
1297
+ 1. Identify the palette color name from the [v7 array](https://github.com/coinbase/cds-staging/blob/v7/packages/common/src/palette/constants.ts#L81-L122)
1298
+ 2. Find the corresponding new color token from the [color mapping tables](#token-updates)
1299
+ 3. Replace array access with direct token name
1300
+
1301
+ **defaultPalette / usePaletteConfig:**
1302
+
1303
+ ```tsx
1304
+ // ❌ Before (v7)
1305
+ import { defaultPalette } from '@coinbase/cds-common/palette/constants';
1306
+ import { usePaletteConfig } from '@coinbase/cds-common/palette/usePaletteConfig';
1307
+
1308
+ // ✅ After (v8) - CSS Variables
1309
+ const bgColor = 'var(--color-bg)';
1310
+
1311
+ // Or using useTheme
1312
+ const theme = useTheme();
1313
+ const bg = theme.color.bg;
1314
+
1315
+ // If passing to ThemeProvider, use coinbaseTheme instead:
1316
+ import { coinbaseTheme } from '@coinbase/cds-web/themes/coinbaseTheme';
1317
+ ```
1318
+
1319
+ ### Icon Migration Instructions
1320
+
1321
+ _See [Icon Updates](#icon-updates) for overview_
1322
+
1323
+ #### Icon Components with Active States
1324
+
1325
+ _Related to [Active State Changes](#icon-updates) mentioned above_
1326
+
1327
+ **Component-to-Prop Mapping:**
1328
+
1329
+ - **Icon**: `['name', 'active']`
1330
+ - **CellMedia**: `['name', 'active']`
1331
+ - **DotSymbol**: `['iconName', 'active']`
1332
+ - **IconButton**: `['name', 'active']`
1333
+ - **InputIcon**: `['name', 'active']`
1334
+ - **InputIconButton**: `['name', 'active']`
1335
+ - **Banner**: `['startIcon', 'startIconActive']`
1336
+ - **Button**: `[['startIcon', 'startIconActive'], ['endIcon', 'endIconActive']]`
1337
+
1338
+ **UI Icon Exceptions List:**
1339
+ Only apply active prop logic if the icon name is in this list: `add`, `affiliates`, `airdrop`, `artwork`, `avatar`, `bell`, `book`, `briefcase`, `calculator`, `camera`, `chartBar`, `chartPie`, `chartPieCircle`, `chatBubble`, `circleCheckmark`, `circleCross`, `clock`, `coinbaseOne`, `crypto`, `cryptobasics`, `currencies`, `defi`, `dot`, `email`, `error`, `ethereum`, `flame`, `games`, `gavel`, `gear`, `giftCard`, `group`, `heart`, `home`, `info`, `institute`, `keyboard`, `lightbulb`, `lightningBolt`, `lock`, `marketCap`, `megaphone`, `microphone`, `music`, `newsFeed`, `newsletter`, `nft`, `orderHistory`, `paperAirplane`, `passport`, `pencil`, `play`, `profile`, `questionMark`, `regulated`, `safe`, `save`, `shield`, `sortDoubleArrow`, `sortDown`, `sortDownCenter`, `sortUp`, `sortUpCenter`, `soundOff`, `soundOn`, `sparkle`, `speaker`, `stake`, `taxesReceipt`, `telephone`, `thumbsDown`, `thumbsUp`, `trashCan`, `trophy`, `unlock`, `verifiedBadge`, `visibleFilled`, `wallet`, `warning`, `wrapToken`.
1340
+
1341
+ **Steps:**
1342
+
1343
+ If the icon name ends with Active or Inactive:
1344
+
1345
+ 1. Remove the suffix from the icon name
1346
+ 2. Add the active prop for icons with Active suffix
1347
+
1348
+ **Example:**
1349
+
1350
+ ```tsx
1351
+ // ❌ Before
1352
+ <Icon name="bellActive" />
1353
+ <Icon name="heartInactive" />
1354
+ <Button startIcon="bellActive" endIcon="heartInactive" />
1355
+
1356
+ // ✅ After
1357
+ <Icon name="bell" active />
1358
+ <Icon name="heart" />
1359
+ <Button startIcon="bell" startIconActive endIcon="heart" />
1360
+ ```
1361
+
1362
+ #### Migrating bordered Icon Prop
1363
+
1364
+ _Related to [Removed bordered Prop](#icon-updates) mentioned above_
1365
+
1366
+ **Steps:**
1367
+
1368
+ 1. Find all instances using regex: `<Icon\s+[^>]*\bbordered\b[^>]*>`
1369
+ 2. Remove the `bordered` prop
1370
+ 3. Wrap the Icon in a bordered Box
1371
+
1372
+ **Example:**
1373
+
1374
+ ```tsx
1375
+ // ❌ Before
1376
+ <Icon name="info" bordered />
1377
+
1378
+ // ✅ After
1379
+ <Box bordered borderRadius={1000} borderColor="fgPrimary">
1380
+ <Icon name="info" />
1381
+ </Box>
1382
+ ```
1383
+
1384
+ ### Component Migration Instructions
1385
+
1386
+ _See [Component Updates](#component-updates) for overview_
1387
+
1388
+ #### Migrating NavigationIcon/NavigationIconButton
1389
+
1390
+ _Related to [Removed Components](#component-updates) mentioned above_
1391
+
1392
+ **Steps:**
1393
+
1394
+ 1. Remove imports:
1395
+ ```tsx
1396
+ import { NavigationIcon } from '@coinbase/cds-web/icons';
1397
+ import { NavigationIconButton } from '@coinbase/cds-web/buttons';
1398
+ ```
1399
+ 2. Replace with:
1400
+ ```tsx
1401
+ import { Icon } from '@coinbase/cds-web/icons';
1402
+ import { IconButton } from '@coinbase/cds-web/buttons/IconButton';
1403
+ ```
1404
+ 3. Update component usage:
1405
+
1406
+ ```tsx
1407
+ // ❌ Before
1408
+ <NavigationIcon name="home" />
1409
+ <NavigationIconButton name="settings" onClick={handleClick} />
1410
+
1411
+ // ✅ After
1412
+ <Icon name="home" />
1413
+ <IconButton name="settings" onClick={handleClick} />
1414
+ ```
1415
+
1416
+ #### Migrating InteractableContent
1417
+
1418
+ _Related to [Removed Components](#component-updates) mentioned above_
1419
+
1420
+ **Steps:**
1421
+
1422
+ 1. Remove import: `import { InteractableContent } from '@coinbase/cds-web/system';`
1423
+ 2. Import Interactable: `import { Interactable } from '@coinbase/cds-web/system';`
1424
+ 3. Replace all usage: `<InteractableContent>` → `<Interactable>`
1425
+
1426
+ #### Migrating Responsive Props
1427
+
1428
+ _Related to [Responsive Props](#component-updates) mentioned above_
1429
+
1430
+ The `responsiveConfig` prop migration is automated by the migration script, but here's the pattern:
1431
+
1432
+ ```tsx
1433
+ // ❌ Before
1434
+ const responsiveConfig = { desktop: { gap: 2 }, tablet: { gap: 3 } };
1435
+ <Box responsiveConfig={responsiveConfig}>Content</Box>
1436
+
1437
+ // ✅ After
1438
+ <Box gap={{ desktop: 2, tablet: 3 }}>Content</Box>
1439
+ ```
1440
+
1441
+ #### Migrating Breakpoints & Media Queries
1442
+
1443
+ _Related to [Breakpoints & Media Queries](#component-updates) mentioned above_
1444
+
1445
+ **Steps:**
1446
+
1447
+ 1. Update import paths
1448
+ 2. Update breakpoint values (note the changes)
1449
+
1450
+ ```tsx
1451
+ // ❌ Before (v7)
1452
+ import { deviceBreakpoints, deviceMqs } from '@coinbase/cds-web/layout/breakpoints';
1453
+
1454
+ // ✅ After (v8)
1455
+ import { breakpoints, media } from '@coinbase/cds-web/styles/media';
1456
+ ```
1457
+
1458
+ **Note:** Breakpoint values have changed. For example, `phone` now starts at `0` and `media.phone` is a `max-width` query.
1459
+
1460
+ #### Migrating overflowClassName
1461
+
1462
+ _Related to [Removed Utilities](#component-updates) mentioned above_
1463
+
1464
+ **Steps:**
1465
+
1466
+ 1. Remove the import of `overflowClassName`
1467
+ 2. Replace with equivalent CSS styles
1468
+
1469
+ ```tsx
1470
+ // ❌ Before (v7)
1471
+ import { overflowClassName } from '@coinbase/cds-web/cells/Cell';
1472
+
1473
+ // ✅ After (v8)
1474
+ const overflowStyles = {
1475
+ overflow: 'auto',
1476
+ textOverflow: 'unset',
1477
+ whiteSpace: 'normal',
1478
+ };
1479
+ ```
1480
+
1481
+ ### Type Migration Instructions
1482
+
1483
+ _See [Type Updates](#type-updates) for overview_
1484
+
1485
+ #### Migrating Polymorphic Component Types
1486
+
1487
+ _Related to [Polymorphic Component Props](#type-updates) mentioned above_
1488
+
1489
+ **BoxElement:**
1490
+
1491
+ ```tsx
1492
+ // ❌ Before (v7)
1493
+ import { BoxElement } from '@coinbase/cds-web/layout/Box';
1494
+ type MyProps = { as?: BoxElement };
1495
+
1496
+ // ✅ After (v8) - Option 1
1497
+ import { BoxDefaultElement } from '@coinbase/cds-web/layout/Box';
1498
+ type MyProps = VStackProps<BoxDefaultElement>;
1499
+
1500
+ // ✅ After (v8) - Option 2
1501
+ type MyProps = { as?: keyof JSX.IntrinsicElements };
1502
+ ```
1503
+
1504
+ **TextProps:**
1505
+
1506
+ ```tsx
1507
+ // ❌ Before (v7)
1508
+ import { TextProps } from '@coinbase/cds-web/typography/Text';
1509
+
1510
+ // ✅ After (v8)
1511
+ import { TextProps, TextDefaultElement } from '@coinbase/cds-web/typography/Text';
1512
+
1513
+ // Usage
1514
+ type MyProps = {
1515
+ textProps: TextProps<'h1'>; // specific element
1516
+ defaultTextProps: TextProps<TextDefaultElement>; // default element
1517
+ };
1518
+ ```
1519
+
1520
+ **LinkTypography:**
1521
+
1522
+ ```tsx
1523
+ // ❌ Before (v7)
1524
+ import { LinkTypography } from '@coinbase/cds-common/types/LinkBaseProps';
1525
+ type FontProp = LinkTypography;
1526
+
1527
+ // ✅ After (v8)
1528
+ import { LinkProps, LinkDefaultElement } from '@coinbase/cds-web/typography/Link';
1529
+ type FontProp = LinkProps<LinkDefaultElement>['font'];
1530
+ ```
1531
+
1532
+ #### Migrating Removed Types
1533
+
1534
+ _Related to [Removed Types](#type-updates) mentioned above_
1535
+
1536
+ **HTMLNonHeadingTextTags:**
1537
+
1538
+ ```tsx
1539
+ // ❌ Before (v7)
1540
+ import { HTMLNonHeadingTextTags } from '@coinbase/cds-web/typography';
1541
+
1542
+ // ✅ After (v8) - Define locally
1543
+ type HTMLNonHeadingTextTags = 'p' | 'span' | 'div' | 'label' | 'legend' | 'caption';
1544
+ ```
1545
+
1546
+ **NoopFn:**
1547
+
1548
+ ```tsx
1549
+ // ❌ Before (v7)
1550
+ import { NoopFn } from '@coinbase/cds-common/utils/mockUtils';
1551
+
1552
+ // ✅ After (v8)
1553
+ type NoopFn = () => void;
1554
+ ```
1555
+
1556
+ **SetState:**
1557
+
1558
+ ```tsx
1559
+ // ❌ Before (v7)
1560
+ import { SetState } from '@coinbase/cds-common/types';
1561
+
1562
+ // ✅ After (v8)
1563
+ type SetState<T> = React.Dispatch<React.SetStateAction<T>>;
1564
+ ```
1565
+
1566
+ **Overflow:**
1567
+
1568
+ ```tsx
1569
+ // ❌ Before (v7)
1570
+ import { Overflow } from '@coinbase/cds-web/types';
1571
+
1572
+ // ✅ After (v8)
1573
+ type Overflow = {
1574
+ overflow?: 'visible' | 'hidden' | 'scroll' | 'auto' | 'clip';
1575
+ };
1576
+ ```
1577
+
1578
+ **IconPixelSize:**
1579
+
1580
+ ```tsx
1581
+ // ❌ Before (v7)
1582
+ import { IconPixelSize } from '@coinbase/cds-common/types/IconSize';
1583
+
1584
+ // ✅ After (v8)
1585
+ type IconPixelSize = 8 | 12 | 16 | 24 | 32;
1586
+ ```
1587
+
1588
+ **GapSpacing:**
1589
+
1590
+ ```tsx
1591
+ // ❌ Before (v7)
1592
+ import { GapSpacing } from '@coinbase/cds-common/types/TooltipBaseProps';
1593
+
1594
+ // ✅ After (v8)
1595
+ import type { ThemeVars } from '@coinbase/cds-common/core/theme';
1596
+ type GapSpacing = ThemeVars.Space;
1597
+ ```
1598
+
1599
+ ### Hook Migration Instructions
1600
+
1601
+ _Cross-references to various sections above_
1602
+
1603
+ #### Migrating useAccessibleForeground
1604
+
1605
+ <Tag intent="promotional">Migration Script ✓</Tag>
1606
+
1607
+ _Related to color token changes in [Token Updates](#token-updates)_
1608
+
1609
+ ```tsx
1610
+ // ❌ Before (v7)
1611
+ import { useAccessibleForeground } from '@coinbase/cds-web/color/useAccessibleForeground';
1612
+
1613
+ const MyComponent = () => {
1614
+ const backgroundColor = 'rgb(255, 0, 0)';
1615
+ const foregroundColor = useAccessibleForeground({
1616
+ background: backgroundColor,
1617
+ color: 'auto',
1618
+ usage: 'normalText',
1619
+ });
1620
+
1621
+ return <div style={{ backgroundColor, color: foregroundColor }}>Content</div>;
1622
+ };
1623
+
1624
+ // ✅ After (v8)
1625
+ import { getAccessibleColor } from '@coinbase/cds-common/utils/getAccessibleColor';
1626
+
1627
+ const MyComponent = () => {
1628
+ const backgroundColor = 'rgb(255, 0, 0)';
1629
+ const foregroundColor = getAccessibleColor({
1630
+ background: backgroundColor,
1631
+ foreground: 'auto', // Can only be 'auto' or undefined
1632
+ usage: 'normalText',
1633
+ });
1634
+
1635
+ return <div style={{ backgroundColor, color: foregroundColor }}>Content</div>;
1636
+ };
1637
+ ```
1638
+
1639
+ #### Migrating useMergedRef
1640
+
1641
+ ```tsx
1642
+ // ❌ Before (v7)
1643
+ import { useMergedRef } from '@coinbase/cds-common/hooks/useMergedRef';
1644
+ const mergedRef = useMergedRef(ref1, ref2);
1645
+
1646
+ // ✅ After (v8)
1647
+ import { useMergeRefs } from '@coinbase/cds-common/hooks/useMergeRefs';
1648
+ const mergedRef = useMergeRefs(ref1, ref2);
1649
+ ```
1650
+
1651
+ #### Migrating useToggler
1652
+
1653
+ ```tsx
1654
+ // ❌ Before (v7)
1655
+ import { useToggler } from '@coinbase/cds-common/hooks/useToggler';
1656
+ const [isOpen, toggleIsOpen] = useToggler(false);
1657
+
1658
+ // ✅ After (v8)
1659
+ import React from 'react';
1660
+ const [isOpen, setIsOpen] = React.useState(false);
1661
+ const toggleIsOpen = () => setIsOpen((prev) => !prev);
1662
+ ```
1663
+
1664
+ #### Migrating useSpectrumConditional
1665
+
1666
+ _Related to theming changes in [Theming Updates](#theming-updates)_
1667
+
1668
+ ```tsx
1669
+ // ❌ Before (v7)
1670
+ import { useSpectrumConditional } from '@coinbase/cds-common/hooks/useSpectrumConditional';
1671
+ const value = useSpectrumConditional(config);
1672
+
1673
+ // ✅ After (v8)
1674
+ import { useTheme } from '@coinbase/cds-web/hooks/useTheme';
1675
+ const theme = useTheme();
1676
+ const value = config(theme.activeColorScheme);
1677
+ ```
1678
+
1679
+ #### Migrating useInteractableHeight
1680
+
1681
+ ```tsx
1682
+ // ❌ Before (v7)
1683
+ import { useInteractableHeight } from '@coinbase/cds-common/hooks/useInteractableHeight';
1684
+ const height = useInteractableHeight(compact);
1685
+
1686
+ // ✅ After (v8)
1687
+ import { interactableHeight } from '@coinbase/cds-common/tokens/interactableHeight';
1688
+ const height = compact ? interactableHeight.compact : interactableHeight.regular;
1689
+ ```
1690
+
1691
+ #### Migrating useIconSize
1692
+
1693
+ ```tsx
1694
+ // ❌ Before (v7)
1695
+ import { useIconSize } from '@coinbase/cds-web/hooks/useIconSize';
1696
+ const { iconSize } = useIconSize(size);
1697
+
1698
+ // ✅ After (v8)
1699
+ import { useTheme } from '@coinbase/cds-web/hooks/useTheme';
1700
+ const theme = useTheme();
1701
+ const iconSize = theme.iconSize[size];
1702
+ ```
1703
+
1704
+ #### Migrating useAvatarSize
1705
+
1706
+ ```tsx
1707
+ // ❌ Before (v7)
1708
+ import { useAvatarSize } from '@coinbase/cds-mobile/hooks/useAvatarSize';
1709
+ const avatarSize = useAvatarSize(size);
1710
+
1711
+ // ✅ After (v8)
1712
+ import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
1713
+ const theme = useTheme();
1714
+ const avatarSize = theme.avatarSize[size];
1715
+ ```
1716
+
1717
+ #### Migrating Scale-Related Hooks (No Direct Replacement)
1718
+
1719
+ _Related to scale system removal in [Theming Updates](#scaledensity-system-removed)_
1720
+
1721
+ **useScale:**
1722
+
1723
+ ```tsx
1724
+ // ❌ Before (v7) - Scale-based rendering
1725
+ const MyComponent = () => {
1726
+ const scale = useScale();
1727
+ if (scale === 'xSmall') {
1728
+ return <CompactLayout />;
1729
+ }
1730
+ return <NormalLayout />;
1731
+ };
1732
+
1733
+ // ✅ After (v8) - Direct component choice or user preference
1734
+ const MyComponent = ({ isCompact }: { isCompact?: boolean }) => {
1735
+ if (isCompact) {
1736
+ return <CompactLayout />;
1737
+ }
1738
+ return <NormalLayout />;
1739
+ };
1740
+
1741
+ // Or custom theme-based detection
1742
+ const useIsDenseTheme = () => {
1743
+ const theme = useTheme();
1744
+ return theme.id === 'dense-theme' || theme.space[2] < 16;
1745
+ };
1746
+ ```
1747
+
1748
+ **useScaleConditional:**
1749
+
1750
+ ```tsx
1751
+ // ❌ Before (v7)
1752
+ import { useScaleConditional } from '@coinbase/cds-common/scale/useScaleConditional';
1753
+ const size = useScaleConditional(mediaSize);
1754
+
1755
+ // ✅ After (v8)
1756
+ const size = mediaSize.normal; // Access values directly
1757
+ ```
1758
+
1759
+ </MDXArticle>
1760
+ </MDXSection>
1761
+
1762
+ </VStack>