--- id: v8-migration-guide title: v8 Migration Guide slug: /guides/v8-migration-guide hide_title: true --- import { MDXSection } from '@site/src/components/page/MDXSection'; import { MDXArticle } from '@site/src/components/page/MDXArticle'; import { ContentHeader } from '@site/src/components/page/ContentHeader'; import { VStack } from '@coinbase/cds-web/layout'; import { Tag } from '@coinbase/cds-web/tag/Tag'; import { Icon } from '@coinbase/cds-web/icons'; ## Introduction CDS v8 is our most feature packed release ever! Including but not limited to: - 🔮 Expanded styling and customization options - 🔥 Faster renders and smaller flamegraphs - 🦾 Improved accessibility of components and theming - 🧩 Simplified and more predictable internal architecture 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 🏎️ If you experience any trouble migrating we're ready to help! Just reach out via Slack. ## New Packages - `@coinbase/cds-common@8.1.0` - `@coinbase/cds-mobile@8.1.0` - `@coinbase/cds-mobile-visualization@3.0.0` - `@coinbase/cds-web@8.1.0` - `@coinbase/cds-web-visualization@3.0.0` - `@coinbase/cds-icons@5.0.0` - `@coinbase/cds-lottie-files@3.0.0` ## Migration Script 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. ### What the Migration Script Automates The migration script handles these transformations automatically: - **Icon migrations**: Active/inactive suffix removal, renamed icons, and active prop additions - **Color token updates**: Converts old color names to new semantic tokens - **Border radius/width tokens**: Updates string tokens to numeric values and CSS variables - **Import path updates**: Fixes outdated import paths throughout your codebase - **Component prop changes**: Updates `responsiveConfig` to direct responsive props - **Hook migrations**: Updates `useSpectrum`, `useAccessibleForeground`, and other deprecated hooks Look for the Migration Script ✓ tags throughout this guide to identify what's automated. ### Running the Migration Script (Internal to Coinbase) For detailed instructions on running the migration script, refer to the Migrator Guide, reach out via Slack if you need help finding the guide. ### What Requires Manual Migration While the script handles most changes, some breaking changes require manual intervention: - **ThemeProvider setup**: Converting from legacy providers to the new ThemeProvider - **Scale/density system removal**: Creating custom dense themes - **Custom styling**: Updating CSS-in-JS and styled components - **Type definitions**: Updating polymorphic component prop types - **Complex component patterns**: Advanced usage that can't be automatically detected ## Dependency Updates ### Linaria Dependency Requirements **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. ```json { "dependencies": { "@linaria/core": "^6.0.0" } } ``` This is required if your application directly imports from `@linaria/core`: ```tsx import { css, cx } from '@linaria/core'; ``` **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: ```tsx // ❌ Requires @linaria/core dependency import { cx } from '@linaria/core'; // ✅ No additional dependency needed import { cx } from '@coinbase/cds-web'; ``` ## 💥 Breaking Change Overview Here's a high-level overview of the major breaking changes in v8: ### 🎨 Theming System Changes - **New ThemeProvider**: Requires `theme` and `activeColorScheme` props (no defaults) - **Provider consolidation**: `SpectrumProvider`, `DarkModeProvider`, `LightModeProvider`, and scale providers replaced by single `ThemeProvider` - **Spectrum vs Color**: Distinction between spectrum (`"r,g,b"`) and color (CSS values) - prefer color tokens - **CSS variables**: Preferred way to access theme values on web for performance - **No inheritance**: ThemeProvider no longer auto-inherits from parent providers - **Color scheme classes**: ThemeProvider adds `.dark`/`.light` classes to container - **Scale/density removed**: No scale system - create custom themes for dense styles - **Theme inversion**: `invertSpectrum` → `invertColorScheme`, new `InvertedThemeProvider` ### 🎭 Style System Changes - **Safari support**: Requires Safari 15.4+ for web (CSS layers, `:focus-visible`, `:has()`) - **CSS layers**: All CDS styles scoped to `@layer cds` for better specificity control - **CSS reset**: New global styles override browser defaults for polymorphic components - **Improved polymorphism**: Better type safety for polymorphic components with `as` prop - **Elevation simplified**: Streamlined system without `ElevationProvider`/`useElevationStyles` - **CSS-in-JS**: Static CSS variables and Linaria-compiled styles instead of runtime calculations ### 🪙 Token Changes - **Color tokens**: Complete redesign with semantic naming: - Foreground: `foreground` → `fg`, `primary` → `fgPrimary` - Background: `background` → `bg`, `primary` → `bgPrimary` - Border: `line` → `bgLine`, `primary` → `bgLinePrimary` - **Border radius**: String tokens → numeric (`rounded` → `200`, `roundedFull` → `1000`) - **Border width**: String tokens → numeric (`button` → `100`, `focusRing` → `200`) - **Import paths**: Many token imports moved to new package locations ### ⭐ Icon Changes - **Active states**: Controlled by `active` prop instead of icon name suffixes (`starFilled` → ``) - **Renamed icons**: Several icons renamed for clarity - **Removed props**: `bordered` prop removed from Icon component - **Removed components**: `NavigationIcon` and `NavigationIconButton` removed ### 🧩 Component Changes - **Responsive props**: `responsiveConfig` prop removed, use direct responsive props - **Media queries**: `deviceBreakpoints`/`deviceMqs` → `breakpoints`/`media` - **Removed providers**: `DevicePreferencesProvider`, `BreakpointsProvider`, `FeatureFlagProvider` - **Removed components**: Several utility components removed or renamed (`InteractableContent` → `Interactable`) - **Import paths**: Component import paths updated to new package structure ### 🔧 Hook & Utility Changes - **useTheme**: Replaces `useSpectrum`, `useScale`, and other theming hooks - **Accessibility**: `useAccessibleForeground` → `getAccessibleColor` with new API - **Spacing**: `useSpacingScale`/`useSpacingValue` → direct theme token access - **Typography**: `useTypographyStyles` → direct theme property access - **Scale hooks**: `useScale`, `useScaleConditional` removed (no scale system) - **Palette utilities**: `paletteValueToRgbaString`, `usePalette` → theme-based approach ### 📝 Type Changes - **Polymorphic types**: Now require type arguments (`TextProps<'h1'>`, `BoxProps<'div'>`) - **Default elements**: `TextDefaultElement`, `BoxDefaultElement` exported for defaults - **Removed types**: `HTMLNonHeadingTextTags`, `NoopFn`, `SetState`, `Overflow`, `IconPixelSize` - **Updated types**: `GapSpacing` → `ThemeVars.Space` ## Theming Updates ### The New ThemeProvider 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. **Basic Setup:** ```tsx import { ThemeProvider } from '@coinbase/cds-web/system/ThemeProvider'; import { defaultTheme } from '@coinbase/cds-web/themes/defaultTheme'; const App = () => { return ( ); }; ``` **Custom Theme:** ```tsx const customTheme = { ...defaultTheme, lightColor: { ...defaultTheme.lightColor, bgPrimary: 'rgb(255, 0, 0)', }, space: { ...defaultTheme.space, 5: 32, }, }; ``` ### The useTheme Hook The `useTheme()` hook provides access to the current theme and active color scheme: ```tsx const MyComponent = () => { const theme = useTheme(); console.log(theme.activeColorScheme); // "light" or "dark" console.log(theme.spectrum); // Reference to lightSpectrum or darkSpectrum console.log(theme.color); // Reference to lightColor or darkColor console.log(theme.color.bgPrimary); // "rgb(0,82,255)" or "rgb(87,139,250)" console.log(theme.space[2]); // "16px" console.log(theme.borderRadius[200]); // "8px" console.log(theme.fontSize.display3); // "2.5rem" }; ``` **Performance Note:** Whenever possible, use CSS variables on web instead of the `useTheme()` hook to ensure best performance. ### Note about Spectrum vs Color 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. ```tsx const lightSpectrum = { red60: '207,32,47', }; const theme = { lightSpectrum, lightColor: { bgNegative: `rgb(${lightSpectrum.red60})`, }, }; // In components: const theme = useTheme(); console.log(theme.spectrum.red60); // "207,32,47" console.log(theme.color.bgNegative); // "rgb(207,32,47)" ``` ### CSS Variables (Web) On web, `ThemeProvider` creates CSS variables for all theme values: | JS variable | CSS variable | | ------------------------- | -------------------- | | `theme.color.bgPrimary` | `--color-bgPrimary` | | `theme.space[2]` | `--space-2` | | `theme.borderRadius[200]` | `--borderRadius-200` | ### Color Scheme Classes (Web) 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. ```css const myStyles = css` .dark { background-image: url('http://example.com/dark.png'); } .light { background-image: url('http://example.com/light.png'); } `; ``` ### ThemeProvider Requirements 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. ### ThemeProvider Inheritance The ThemeProvider no longer automatically inherits and merges themes from parent ThemeProviders. However you can manually inherit the theme if you want: ```tsx const MyPage = () => { const theme = useTheme(); const customTheme = { ...theme, fontFamily: { ...theme.fontFamily, label1: 'Arial', }, }; return ( Customized theming! ); }; ``` ### Scale/Density System Removed 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. 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. ### Inverting the Theme 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`. 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. ```tsx const MyComponent = ({ invertColorScheme }) => { const Wrapper = invertColorScheme ? InvertedThemeProvider : React.Fragment; return Hello world; }; ``` ### Removed Theming APIs The following theming-related APIs have been removed: **Providers:** - `SpectrumProvider` / `RootSpectrumProvider` - [see migration instructions](#migrating-rootspectrumprovider) - `DarkModeProvider` / `LightModeProvider` - [see migration instructions](#migrating-darkmodeprovider--lightmodeprovider) - `ScaleProvider` / `RootScaleProvider` / `DenseScaleProvider` / `NormalScaleProvider` - [see dense theme migration](#creating-dense-themes) **Hooks:** - `useSpectrum` - Replaced by `useTheme` hook - `useScale` / `useScaleConditional` - [see migration instructions](#migrating-scale-related-hooks-no-direct-replacement) - `useSpectrumConditional` - [see migration instructions](#migrating-usespectrumconditional) ## Style Updates ### Safari Web Support 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()`. ### CSS Layers 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: ```css @layer cds { .hello-world { color: red; } } ``` 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. ### New Web Global Styles 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). ### Improved Polymorphism Many web components are now fully polymorphic with strong type checking: ```tsx // Without the `as` prop, href throws a type error ); }; ``` #### Migrating BreakpointsProvider **Steps:** 1. Remove the `BreakpointsProvider` import 2. Add `import { MediaQueryProvider } from '@coinbase/cds-web/system/MediaQueryProvider'` 3. Replace `BreakpointsProvider` with `MediaQueryProvider` 4. Add the `defaultValues` prop if needed ```tsx // ❌ Before (v7) import { BreakpointsProvider } from '@coinbase/cds-web/system/BreakpointsProvider'; // ✅ After (v8) import { MediaQueryProvider } from '@coinbase/cds-web/system/MediaQueryProvider'; const App = () => ( ); ``` #### Migrating RootSpectrumProvider **Steps:** 1. Replace `RootSpectrumProvider` with `ThemeProvider` 2. Add your own device color scheme detection logic using `useDeviceColorScheme()` hook 3. Implement user preference state management ```tsx // ❌ Before (v7) import { RootSpectrumProvider } from '@coinbase/cds-mobile/system'; // ✅ After (v8) - Manual override with state management import { ThemeProvider } from '@coinbase/cds-mobile/system/ThemeProvider'; import { defaultTheme } from '@coinbase/cds-mobile/themes/defaultTheme'; import { useDeviceColorScheme } from '@coinbase/cds-mobile/hooks/useDeviceColorScheme'; const App = () => { const deviceColorScheme = useDeviceColorScheme(); const [userPreference, setUserPreference] = useState<'system' | 'light' | 'dark'>('system'); const activeColorScheme = userPreference === 'system' ? deviceColorScheme : userPreference; return ( {/* Somewhere in your settings */} ); }; ``` #### Migrating DarkModeProvider / LightModeProvider **Steps:** 1. Remove `DarkModeProvider` and `LightModeProvider` imports 2. Replace with `ThemeProvider` that has `activeColorScheme` set to `"dark"` or `"light"` ```tsx // ❌ Before (v7) import { DarkModeProvider, LightModeProvider } from '@coinbase/cds-mobile/system'; // ✅ After (v8) import { ThemeProvider } from '@coinbase/cds-mobile/system/ThemeProvider'; import { defaultTheme } from '@coinbase/cds-mobile/themes/defaultTheme'; ``` #### Migrating FeatureFlagProvider **Steps:** 1. Simply remove `FeatureFlagProvider` from your component tree 2. The benefits it provided are now automatic in v8 ```tsx // ❌ Before (v7) import { FeatureFlagProvider } from '@coinbase/cds-web/system'; // ✅ After (v8) // Simply remove the provider - modern behaviors like CSS gap are now default ``` **What was automated:** - CSS gap support - Fabric support - Other modern behaviors that required opt-in #### Migrating ElevationConfigsProvider **Steps:** 1. Remove `ElevationConfigsProvider` from your component tree 2. The elevation system has been simplified and no longer needs this provider ```tsx // ❌ Before (v7) import { ElevationConfigsProvider } from '@coinbase/cds-mobile/system'; // ✅ After (v8) // Simply remove the provider - elevation is now handled directly by components ``` #### Creating Dense Themes _Related to the scale system removal mentioned in [Theming Updates](#theming-updates)_ **Steps:** 1. Copy the example `coinbaseDenseTheme` from CDS 2. Create theme switching logic **Example:** ```tsx import { ThemeProvider } from '@coinbase/cds-web/system/ThemeProvider'; import { coinbaseDenseTheme } from '@coinbase/cds-web/themes/coinbaseDenseTheme'; import { coinbaseTheme } from '@coinbase/cds-web/themes/coinbaseTheme'; // override the dense theme with your own values if needed const myDenseTheme = { ...coinbaseDenseTheme, id: 'dense-theme', space: { '0': 0, '0.25': 2, '0.5': 4, '0.75': 6, '1': 8, '1.5': 10, '2': 12, // vs 16 in default '3': 16, // vs 24 in default '4': 20, // vs 32 in default '5': 24, // vs 40 in default // ... other smaller values }, fontSize: { headline: 14, // vs 16 in default body: 14, // vs 16 in default // ... other smaller font sizes }, // ... other dense tokens }; const App = ({ activeColorScheme }) => { const [isDense, setIsDense] = React.useState(false); const theme = isDense ? myDenseTheme : coinbaseTheme; return ( ); }; ``` ### Style Migration Instructions _See [Style Updates](#style-updates) for overview_ #### Migrating useThemeProviderStyles **Steps:** 1. Update the import path: `import { useThemeProviderStyles } from '@coinbase/cds-web/system/ThemeProvider';` 2. Remove `className` references (no longer returned) 3. Update hook usage ```tsx // ❌ Before (v7) const { className, style } = useThemeProviderStyles(); // ✅ After (v8) import { useThemeProviderStyles } from '@coinbase/cds-web/system/ThemeProvider'; const style = useThemeProviderStyles(); ``` #### Migrating useTypographyStyles _Related to new style tokens mentioned in [Style Updates](#style-updates)_ **On Web:** ```tsx // ❌ Before (v7) const styles = useTypographyStyles('body'); // ✅ After (v8) const styles = { fontFamily: 'var(--fontFamily-text)', fontSize: 'var(--fontSize-body)', lineHeight: 'var(--lineHeight-body)', }; // For display typography: const displayStyles = { fontFamily: 'var(--fontFamily-display1)', fontSize: 'var(--fontSize-display1)', fontWeight: 'var(--fontWeight-display1)', lineHeight: 'var(--lineHeight-display1)', }; ``` **On Mobile:** ```tsx // ❌ Before (v7) const styles = useTypographyStyles('headline'); // ✅ After (v8) const theme = useTheme(); const headlineStyles = useMemo( () => ({ fontSize: theme.fontSize.headline, lineHeight: theme.lineHeight.headline, fontWeight: theme.fontWeight.headline, fontFamily: theme.fontFamily.headline, }), [theme], ); // Or access individual values directly const bodyLineHeight = theme.lineHeight.body; ``` #### Migrating useSpacingStyles **Steps:** 1. Remove the import of `useSpacingStyles` 2. Replace with native padding/margin style properties ```tsx // ❌ Before (v7) const spacingStyles = useSpacingStyles(); // ✅ After (v8) // web const styles = css` padding: var(--space-1) margin: calc(-1 * var(--space-1))) `; // mobile const theme = useTheme(); const styles = { padding: theme.space[1], margin: -theme.space[1], }; ``` ### Token Migration Instructions _See [Token Updates](#token-updates) for overview and mapping tables_ #### Migrating useSpacingScale / useSpacingValue **On Web:** ```tsx // ❌ Before (v7) import { useSpacingValue } from '@coinbase/cds-web/hooks/useSpacingValue'; const paddingValue = useSpacingValue(3); // ✅ After (v8) - CSS Variables const paddingValue = 'var(--space-3)'; // Or direct calculation const paddingValue = 3 * 8; // 24px ``` **On Mobile:** ```tsx // ❌ Before (v7) import { useSpacingValue } from '@coinbase/cds-mobile/hooks/useSpacingValue'; const spacing = useSpacingValue(1); // ✅ After (v8) import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme'; const theme = useTheme(); const spacing = theme.space[1]; ``` #### Migrating borderRadius Tokens _Refer to [Border Radius Token Mapping](#token-updates) table_ **Steps:** 1. Remove the import of `borderRadius` 2. Replace usage with CSS variables or theme tokens ```tsx // ❌ Before (v7) import { borderRadius } from '@coinbase/cds-common/tokens/borderRadius'; const radius = borderRadius.rounded; // ✅ After (v8) - CSS Variables const radius = 'var(--borderRadius-200)'; // Or using useTheme Hook: const theme = useTheme(); const radius = theme.borderRadius[200]; ``` #### Migrating borderWidth Tokens _Refer to [Border Width Token Mapping](#token-updates) table_ **Steps:** 1. Remove the import of `borderWidth` 2. Import `useTheme` if needed 3. Replace with theme tokens ```tsx // ❌ Before (v7) import { borderWidth } from '@coinbase/cds-common/tokens/borderWidth'; const width = borderWidth.button; // ✅ After (v8) import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme'; const theme = useTheme(); const width = theme.borderWidth[100]; ``` #### Migrating Color Palette Functions _Refer to [Color Token Mapping](#token-updates) table_ **paletteValueToRgbaString:** ```tsx // ❌ Before (v7) import { paletteValueToRgbaString } from '@coinbase/cds-common/palette/paletteValueToRgbaString'; const color = paletteValueToRgbaString('green0', activeColorScheme); // ✅ After (v8) import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme'; const theme = useTheme(); const color = `rgba(${theme.spectrum.green0}, 0.1)`; ``` **paletteValueToHex:** ```tsx // ❌ Before (v7) import { paletteValueToHex } from '@coinbase/cds-common/palette/paletteValueToHex'; const color = paletteValueToHex('gray60', activeColorScheme); // ✅ After (v8) import { useTheme } from '@coinbase/cds-web/hooks/useTheme'; const theme = useTheme(); const color = theme.spectrum.gray60; ``` **paletteAliasToRgbaString:** ```tsx // ❌ Before (v7) import { paletteAliasToRgbaString } from '@coinbase/cds-common/palette/paletteAlias'; const color = paletteAliasToRgbaString('primary', activeColorScheme); // ✅ After (v8) import { useTheme } from '@coinbase/cds-web/hooks/useTheme'; const theme = useTheme(); const color = theme.color.fgPrimary; ``` **usePalette:** ```tsx // ❌ Before (v7) import { usePalette } from '@coinbase/cds-web/hooks/usePalette'; const palette = usePalette(); const color = palette.foregroundMuted; // ✅ After (v8) import { useTheme } from '@coinbase/cds-web/hooks/useTheme'; const theme = useTheme(); const color = theme.color.fgMuted; ``` **Palette Constants (paletteForegrounds, paletteBackgrounds, paletteBorders):** ```tsx // ❌ Before (v7) import { paletteBackgrounds, paletteForegrounds, paletteBorders, } from '@coinbase/cds-common/palette/constants'; const bgColor = paletteBackgrounds[1]; const textColor = paletteForegrounds[0]; const borderColor = paletteBorders[2]; // ✅ After (v8) // Use specific color token names instead const bgColor = 'bgAlternate'; const textColor = 'fg'; const borderColor = 'bgLine'; ``` **Steps:** 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) 2. Find the corresponding new color token from the [color mapping tables](#token-updates) 3. Replace array access with direct token name **defaultPalette / usePaletteConfig:** ```tsx // ❌ Before (v7) import { defaultPalette } from '@coinbase/cds-common/palette/constants'; import { usePaletteConfig } from '@coinbase/cds-common/palette/usePaletteConfig'; // ✅ After (v8) - CSS Variables const bgColor = 'var(--color-bg)'; // Or using useTheme const theme = useTheme(); const bg = theme.color.bg; // If passing to ThemeProvider, use coinbaseTheme instead: import { coinbaseTheme } from '@coinbase/cds-web/themes/coinbaseTheme'; ``` ### Icon Migration Instructions _See [Icon Updates](#icon-updates) for overview_ #### Icon Components with Active States _Related to [Active State Changes](#icon-updates) mentioned above_ **Component-to-Prop Mapping:** - **Icon**: `['name', 'active']` - **CellMedia**: `['name', 'active']` - **DotSymbol**: `['iconName', 'active']` - **IconButton**: `['name', 'active']` - **InputIcon**: `['name', 'active']` - **InputIconButton**: `['name', 'active']` - **Banner**: `['startIcon', 'startIconActive']` - **Button**: `[['startIcon', 'startIconActive'], ['endIcon', 'endIconActive']]` **UI Icon Exceptions List:** 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`. **Steps:** If the icon name ends with Active or Inactive: 1. Remove the suffix from the icon name 2. Add the active prop for icons with Active suffix **Example:** ```tsx // ❌ Before