# ThemeProvider **📖 Live documentation:** https://cds.coinbase.com/components/other/ThemeProvider/ Provides the theme context to all child components, and automatically generates CSS Variables for dynamic theming. ## Import ```tsx import { ThemeProvider } from '@coinbase/cds-web' ``` ## Examples import { defaultTheme } from '@coinbase/cds-web/themes/defaultTheme'; import { createThemeCssVars } from '@coinbase/cds-web/core/createThemeCssVars'; import { JSONCodeBlock } from '@site/src/components/page/JSONCodeBlock'; ### ThemeProvider component The ThemeProvider provides the theme context to all child components, and automatically generates CSS Variables for dynamic theming. You must pass the `theme` prop to configure the theme, and the `activeColorScheme` prop to set light or dark mode. ```tsx import { ThemeProvider } from '@coinbase/cds-web/system/ThemeProvider'; import { defaultTheme } from '@coinbase/cds-web/themes/defaultTheme'; const App = () => ( {/* Your app components */} ); ``` :::tip Changing the `activeColorScheme` automatically updates the values returned from the `useTheme` hook and from CSS Variables. ::: ### `useTheme` hook The `useTheme` hook provides access to the current `theme` and `activeColorScheme`. The `color` and `spectrum` objects automatically change based on the `activeColorScheme`. [See the `useTheme` docs here →](/hooks/useTheme) ```jsx const theme = useTheme(); theme.activeColorScheme; // "light" or "dark" theme.spectrum; // Resolves to lightSpectrum or darkSpectrum, depends on activeColorScheme theme.color; // Resolves to lightColor or darkColor, depends on activeColorScheme theme.color.bgPrimary; // "rgb(0,82,255)" or "rgb(87,139,250)", depends on activeColorScheme theme.space[2]; // 16 theme.borderRadius[200]; // 8 theme.fontSize.display3; // "2.5rem" ``` :::tip For best performance, prefer to use CSS Variables instead of the `useTheme` hook whenever possible. ::: ### CSS Variables CSS Variables are created for every value in the theme. For best performance, prefer using CSS Variables instead of the `useTheme` hook whenever possible. ```jsx const theme = useTheme(); theme.color.bgPrimary; // --color-bgPrimary theme.lightColor.bgPrimary; // --lightColor-bgPrimary theme.darkColor.bgPrimary; // --darkColor-bgPrimary theme.spectrum.blue10; // --blue10 theme.lightSpectrum.blue10; // --light-blue10 theme.darkSpectrum.blue10; // --dark-blue10 theme.space[2]; // --space-2 theme.space[0.25]; // --space-0_25 theme.borderRadius[400]; // --borderRadius-400 theme.fontSize.body; // --fontSize-body ``` You can see all the CSS Variables for the `defaultTheme` below. #### CSS Variable inheritance When ThemeProviders are nested, the nested provider only sets CSS variables that differ from its parent. Unchanged values are inherited through the DOM via normal CSS custom property inheritance. This optimization breaks when a ThemeProvider renders **outside** its parent's DOM tree — for example, inside a portal — because CSS inheritance requires DOM ancestry. In these cases, use the `isolated` prop to ensure the ThemeProvider writes all CSS variables: ```tsx {/* All CSS variables are written, regardless of the parent theme */} ``` :::tip CDS overlay components (Modal, Toast, Alert, etc.) handle this automatically via [PortalProvider](/components/overlay/PortalProvider). You only need the `isolated` prop when rendering a ThemeProvider inside a custom portal that is not managed by CDS. ::: ### ThemeProvider classnames The ThemeProvider renders with CSS classnames based on the `activeColorScheme` and the theme's `id`. This allows you to style components based on the `activeColorScheme` or the theme's `id`. ```jsx // Renders with a .cds-default class and a .light class ``` ### Nested themes ThemeProviders can be nested to create theme overrides for specific sections. ```jsx {/* Default theme in light color scheme */} {/* Custom theme in dark color scheme */} ``` #### Overriding theme values When nesting, you may want to override specific color values from the current theme. Overrides must be conditionally applied because we don't enforce that a theme has both light and dark colors defined. ```jsx // Override parts of the parent theme const theme = useTheme(); const customTheme = { ...theme, ...(theme.lightColor && theme.lightSpectrum && { lightColor: { ...theme.lightColor, bg: `rgb(${theme.lightSpectrum.orange50})`, bgPrimary: `rgb(${theme.lightSpectrum.red20})`, bgSecondary: `rgb(${theme.lightSpectrum.blue50})`, }, }), ...(theme.darkColor && theme.darkSpectrum && { darkColor: { ...theme.darkColor, bg: `rgb(${theme.darkSpectrum.orange50})`, bgPrimary: `rgb(${theme.darkSpectrum.red20})`, bgSecondary: `rgb(${theme.darkSpectrum.blue50})`, }, }), } as const satisfies Theme; ``` #### Theme inheritance Nested ThemeProviders do not automatically inherit the theme from their parent provider. You can manually inherit the theme with the `useTheme` hook. ```jsx const Example = () => { // Pass the parent theme down to another ThemeProvider const theme = useTheme(); return ( {children} ); }; ``` ### InvertedThemeProvider component The InvertedThemeProvider automatically inherits from its parent theme and flips the `activeColorScheme` to the opposite value. ```jsx live {/* Default theme in light color scheme */} {/* Default theme in inverse (dark) color scheme */} ``` ## Props | Prop | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `activeColorScheme` | `light \| dark` | Yes | `-` | - | | `theme` | `ThemeConfig` | Yes | `-` | - | | `className` | `string` | No | `-` | - | | `display` | `grid \| ruby \| table \| string & {} \| -moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| none \| block \| inline \| inline-block \| flex \| inline-flex \| inline-grid \| contents \| flow-root \| list-item \| run-in \| -ms-flexbox \| -ms-grid \| -webkit-flex \| flow \| ruby-base \| ruby-base-container \| ruby-text \| ruby-text-container \| table-caption \| table-cell \| table-column \| table-column-group \| table-footer-group \| table-header-group \| table-row \| table-row-group \| -ms-inline-flexbox \| -ms-inline-grid \| -webkit-inline-flex \| inline-list-item \| inline-table` | No | `-` | - | | `isolated` | `boolean` | No | `false` | Use the isolated prop to indicate when ThemeProvider will render outside its parents DOM tree, such as in a portal. An isolated ThemeProvider always inserts all theme CSS variables into the DOM, regardless of what overlaps with parent ThemeProvider instances. | | `motionFeatures` | `FeatureBundle \| LazyFeatureBundle` | No | `domAnimation` | A motion feature bundle, used to selectively bundle specific framer-motion features. You likely wont need to use this this prop. | | `style` | `CSSProperties` | No | `-` | - |