Description
The Theme component is a helper component that lets you create nested theming solutions.
NB: <Theme> wraps its children in a div by default. Use e.g. element="span" to change the wrapper element, or use Theme.Context to skip the wrapper entirely (see below).
import { Theme, useTheme } from '@dnb/eufemia/shared'const Component = () => {const themeName = useTheme()?.namereturn 'My Component'}render(<Theme name="sbanken"><App><MyComponent /></App></Theme>)
From CSS you can use it as so:
.eufemia-theme__sbanken.eufemia-theme[data-name="sbanken"](alternative)
CSS
.eufemia-theme__sbanken .additional-selector {--color-sea-green: var(--sb-color-purple-alternative);}
SCSS
:global(.eufemia-theme__sbanken) {.additional-selector {--color-sea-green: var(--sb-color-purple-alternative);}}
React Hook useTheme
For accessing the theme context, you can use the useTheme Hook. It returns the theme context, with an addition of boolean constants like isSbanken.
import { Theme, useTheme } from '@dnb/eufemia/shared'const Component = () => {// Result: { name: 'sbanken', isUi: false, isSbanken: true, isEiendom: false }const theme = useTheme()const { name, isUi, isSbanken, isEiendom } = theme || {}return null}render(<Theme name="sbanken"><App><MyComponent /></App></Theme>)
NB: If no context is given, the hook will return null.
Theme.Context
You can use Theme.Context to provide theme properties to children without adding a wrapper element. This is useful in cases where you don't want to add an extra DOM element, but still want to provide theme context to the children.
import { Theme } from '@dnb/eufemia/shared'render(<Theme.Context>Children that receive theme context without an extra wrapper element.</Theme.Context>)
Use your component as the wrapper element
You can provide your component as the wrapper. This way no additional HTML Element will be created.
import { Theme } from '@dnb/eufemia/shared'const Component = ({ className ...props }) => {return <div className={className+' more-classes'} {...props} />}render(<Theme name="theme-name"><App><Theme name="sbanken" element={Component}>...</Theme></App></Theme>)
surface property
The surface property can be used to adjust the component's appearance based on the background. It accepts three values: dark, light, and initial.
- Use
darkwhen the content is placed on a dark surface. - Use
lightfor light surfaces. - Use
initialto tell the components to use its default behavior.
import { Theme } from '@dnb/eufemia/shared'render(<Section surface="dark">Children will use the dark surface behavior (ondark).<Theme.Context surface="initial">Children will use their default surface behavior</Theme.Context></Section>)
How surface works
The surface prop is passed through React context, not through a global CSS class. When you set surface="dark" on a <Theme>, <Theme.Context>, or on a supporting component like Section, the value is stored in the Eufemia theme context. Individual components that support dark surfaces — such as Button or Anchor — read the surface value from context and apply their own component-level CSS class (e.g. dnb-button--surface-dark, dnb-anchor--surface-dark).
Wrap an area with <Theme.Context> or <Section> to propagate the surface context to all supporting components inside:
<Theme.Context surface="dark"><Button>I adapt automatically</Button><Anchor href="/path">So do I</Anchor></Theme.Context>
Use surface="initial" to reset components back to their default behavior inside a dark surface context:
<Section surface="dark"><Button>Dark surface button</Button><Theme.Context surface="initial"><Button>Default surface button</Button></Theme.Context></Section>
The colorScheme property (Dark mode)
The Theme component accepts a colorScheme prop that controls dark and light mode.
When set to "auto", it follows the user's system color preference unless overridden by a parent theme or application setting. It uses the prefers-color-scheme media query to detect the system preference.
Dark mode tokens are not included in the default theme import. Import the extra dark mode stylesheet before using colorScheme:
import { Theme } from '@dnb/eufemia/shared'// Required: import dark mode tokensimport '@dnb/eufemia/style/themes/ui/ui-theme-dark-mode--isolated.min.css' // If style isolation is usedrender(<Theme colorScheme="auto"><App /></Theme>)
For guidance on choosing between base, inverse, and ondark token variants in your own components, see the Design Tokens dark mode guide.
Persisting the theme with getTheme and setTheme
Eufemia provides getTheme and setTheme helpers that persist theme state (including colorScheme) to localStorage under the key eufemia-theme.
import { getTheme, setTheme } from '@dnb/eufemia/shared/Theme'// Read the current persisted themeconst theme = getTheme()// { name: 'ui', colorScheme: 'auto', ... }// Update one or more properties (merges with existing state)setTheme({ colorScheme: 'dark' })// With a callbacksetTheme({ name: 'sbanken' }, (updatedTheme) => {console.log(updatedTheme)})
getTheme also supports a ?eufemia-theme=<name> URL query parameter, which overrides the persisted theme name. This is useful for testing or previewing themes via a link.
Preventing dark mode flash (FOUC)
When using colorScheme="system", the resolved color scheme depends on the user's system preference, which is only available in the browser. During server-side rendering (SSR), this can cause a brief flash of the wrong color scheme before React hydrates.
To prevent this, Eufemia provides blocking scripts that run synchronously before the browser paints. They read the stored preference from localStorage and apply the correct CSS classes immediately.
import {ColorSchemeHeadScript,ColorSchemeBodyFirstScript,ColorSchemeBodyLastScript,} from '@dnb/eufemia/shared/ColorSchemeScript'
Place them in your HTML template as follows:
<html><head><ColorSchemeHeadScript /></head><body><ColorSchemeBodyFirstScript />{/* your app content */}<ColorSchemeBodyLastScript /></body></html>
ColorSchemeHeadScript— Resolves the color scheme fromlocalStorage(or falls back to the system preference) and stores it onglobalThis. Place in<head>.ColorSchemeBodyFirstScript— Adds the resolved color-scheme class to<body>. Place as the first child of<body>.ColorSchemeBodyLastScript— Swaps color-scheme classes on server-renderedThemeelements so they match the resolved scheme. Place as the last child of<body>.
Hide or show parts of your component (filter)
With this helper function you show or hide content based on inherited theme properties.
import { Theme, VisibilityByTheme } from '@dnb/eufemia/shared'render(<Theme name="..."><VisibilityByTheme visible="sbanken">Only shown in Sbanken theme</VisibilityByTheme><VisibilityByTheme hidden="eiendom">Only hidden in Eiendom theme</VisibilityByTheme><VisibilityByTheme visible={['sbanken', 'eiendom']}>Only shown in Sbanken or Eiendom theme</VisibilityByTheme><VisibilityByThemevisible={[{ name: 'sbanken' }, { name: 'eiendom' }]}>Only shown in Sbanken or Eiendom theme</VisibilityByTheme><VisibilityByThemevisible={[{ name: 'sbanken' }, { name: 'eiendom', variant: 'blue' }]}>Only shown in Sbanken then or Eiendom theme – that also includes thefictive variant="blue".</VisibilityByTheme></Theme>)
Integrations
When integrating runtime theme switching, your app can be wrapped with this theme component.