App provider

A top level provider for the Design System.

Beta

New and ready to use. We'll provide comms and support for any major changes.

Theming

App provider sets up theming for an app, enabling design tokens to be used.

Theming with design tokens

import React from 'react'; import { Box } from '@atlaskit/primitives/compiled'; import AppProvider from '@atlaskit/app-provider'; function ThemedComponent() { return ( <Box backgroundColor="elevation.surface" padding="space.200"> <Box as="h3"> Theming with design tokens </Box> </Box> ); } function AppProviderTheme() { return ( <AppProvider> <ThemedComponent /> </AppProvider> ); }

Color mode and theme switching

The useColorMode hook can be used to get the active color mode. When the color mode is set to auto, the active color mode will be determined by the user's system preference.

The useTheme hook can be used to get the active themes. The useSetTheme hook can be used to change themes.

Current color mode: light

Current light theme: light

import React from 'react'; import { Box } from '@atlaskit/primitives/compiled'; import AppProvider from '@atlaskit/app-provider'; function ColorModeSwitcher() { const colorMode = useColorMode(); const setColorMode = useSetColorMode(); return ( <Box backgroundColor="elevation.surface" padding="space.200"> <Box as="h3" paddingBlockEnd="space.200"> Current color mode: {colorMode} </Box> <DropdownMenu trigger="Change color mode"> <DropdownItemGroup> <DropdownItem onClick={() => setColorMode('light')}> Light </DropdownItem> <DropdownItem onClick={() => setColorMode('dark')}>Dark</DropdownItem> <DropdownItem onClick={() => setColorMode('auto')}>Auto</DropdownItem> </DropdownItemGroup> </DropdownMenu> </Box> ); } function ThemeSwitcher() { const theme = useTheme(); const setTheme = useSetTheme(); return ( <Box backgroundColor="elevation.surface" padding="space.200"> <Box as="h3" paddingBlockEnd="space.200"> Current light theme: {theme.light} </Box> <DropdownMenu trigger="Change light theme"> <DropdownItemGroup> <DropdownItem onClick={() => setTheme({ light: 'light' })}> Light theme </DropdownItem> </DropdownItemGroup> </DropdownMenu> </Box> ); } function AppProviderTheme() { return ( <AppProvider defaultColorMode="auto"> <ColorModeSwitcher /> <ThemeSwitcher /> </AppProvider> ); }

Sub-tree theming

Use sub-tree theming to apply a different color mode or theme to a specific section of your UI, independently of the rest of the page. This is useful for content that needs a distinct visual treatment.

Nest ThemeProvider inside AppProvider to scope a theme to part of the page.

This sub-tree theme is light mode.

This nested sub-tree theme is dark mode.

import React from 'react'; import AppProvider, { ThemeProvider } from '@atlaskit/app-provider'; import Button from '@atlaskit/button/new'; import { Box, Inline, Stack, Text } from '@atlaskit/primitives/compiled'; function SubTreeThemingExample() { return ( <AppProvider> <ThemeProvider defaultColorMode="light"> <Box backgroundColor="elevation.surface" padding="space.300"> <Stack space="space.200"> <Text as="p">This sub-tree theme is light mode.</Text> <Inline space="space.100"> <Button>Button</Button> </Inline> <ThemeProvider defaultColorMode="dark"> <Box backgroundColor="elevation.surface" padding="space.300"> <Stack space="space.200"> <Text as="p">This nested sub-tree theme is dark mode.</Text> <Inline space="space.100"> <Button>Button</Button> </Inline> </Stack> </Box> </ThemeProvider> </Stack> </Box> </ThemeProvider> </AppProvider> ); }

Portalled content

Components that render into a portal render outside the ThemeProvider's DOM subtree. By default, portalled content inherits the root theme rather than the sub-tree theme.

To support sub-tree theming for portalled content, use the Portal component, which passes the color mode to the content it renders.

Sub-tree theming outside AppProvider

If AppProvider has not yet been adopted in your application, ThemeProvider can still be used standalone to apply scoped theming. In this case, every ThemeProvider including the outermost one behaves as a sub-tree theme. It wraps its children in a scoped div and does not set page-level theme attributes on html or body.

This sub-tree theme is light mode.

This nested sub-tree theme is dark mode.

/** * When used outside of AppProvider, ThemeProvider scopes its theme to its * own subtree only. It does not set page-level theme attributes, so the * page background and other global styles will not be themed. * * For full page theming, use AppProvider at the root of your application. */ import React from 'react'; import { ThemeProvider } from '@atlaskit/app-provider/theme-provider'; import Button from '@atlaskit/button/default/button'; import { Box, Inline, Stack, Text } from '@atlaskit/primitives/compiled'; function SubTreeThemingOutsideAppProviderExample(): React.JSX.Element { return ( <ThemeProvider defaultColorMode="light"> <Box backgroundColor="elevation.surface" padding="space.300"> <Stack space="space.200"> <Text as="p">This sub-tree theme is light mode.</Text> <Inline space="space.100"> <Button>Button</Button> </Inline> <ThemeProvider defaultColorMode="dark"> <Box backgroundColor="elevation.surface" padding="space.300"> <Stack space="space.200"> <Text as="p">This nested sub-tree theme is dark mode.</Text> <Inline space="space.100"> <Button>Button</Button> </Inline> </Stack> </Box> </ThemeProvider> </Stack> </Box> </ThemeProvider> ); } export default SubTreeThemingOutsideAppProviderExample;

Dynamic color mode inversion

A common pattern is to create a panel that always displays the opposite color mode to its surroundings. For example, a dark sidebar in a light-mode app, or a highlighted callout that always contrasts with its parent.

To do this reliably, read the parent color mode with useColorMode(), then call useSetColorMode() inside the sub-tree ThemeProvider to update it reactively.

Avoid relying on defaultColorMode alone for this pattern. The prop is only applied on initial mount and does not react to subsequent changes in the parent's color mode.

Parent panel.

This panel is always the opposite color mode to its parent. It reacts to changes in the parent's color mode automatically.

import React, { useEffect } from 'react'; import AppProvider, { ThemeProvider, useColorMode, useSetColorMode } from '@atlaskit/app-provider'; import Button from '@atlaskit/button/new'; import { Box, Inline, Stack, Text } from '@atlaskit/primitives/compiled'; import type { ThemeColorModes } from '@atlaskit/tokens'; function InvertedPanelContent({ parentColorMode }: { parentColorMode: ThemeColorModes }) { const setColorMode = useSetColorMode(); useEffect(() => { // Always apply the opposite of the parent color mode setColorMode(parentColorMode === 'light' ? 'dark' : 'light'); }, [parentColorMode, setColorMode]); return ( <Box backgroundColor="elevation.surface" padding="space.300"> <Stack space="space.200"> <Text as="p"> This panel is always the opposite color mode to its parent. It reacts to changes in the parent's color mode automatically. </Text> <Inline space="space.100"> <Button>Inverted button</Button> </Inline> </Stack> </Box> ); } function InvertedPanel() { // Read the color mode from the nearest parent ThemeProvider (or AppProvider) const parentColorMode = useColorMode(); return ( <ThemeProvider> <InvertedPanelContent parentColorMode={parentColorMode} /> </ThemeProvider> ); } function DynamicSubTreeThemingExample() { return ( <AppProvider defaultColorMode="light"> <Box backgroundColor="elevation.surface" padding="space.300"> <Stack space="space.200"> <Text as="p">Parent panel.</Text> <InvertedPanel /> </Stack> </Box> </AppProvider> ); }

The routerLinkComponent prop provides support for configuring router links within Design System components.

Support for this is limited as Design System components are being updated, starting with:

This example shows how links can be configured to utilize the router link component supplied by React Resource Router, (opens new window), however any routing library can be used.

import React, { forwardRef, type Ref } from 'react'; import { Link, type LinkProps, RouteComponent, Router, } from 'react-resource-router'; import AppProvider, { type RouterLinkComponentProps } from '@atlaskit/app-provider'; type ReactResourceRouterLinkConfig = Pick<LinkProps, 'to' | 'href' | 'replace'>; const MyRouterLinkComponent = forwardRef( ( { href, children, ...rest }: RouterLinkComponentProps<ReactResourceRouterLinkConfig>, ref: Ref<HTMLAnchorElement>, ) => { // A basic link by passing a string as the component's `href` prop. if (typeof href === 'string') { return ( <Link ref={ref} href={href} {...rest}> {children} </Link> ); } // Advanced link configuration by passing an object as the // component's `href` prop return ( <Link ref={ref} href={href.href} to={href.to} replace={href.replace} {...rest} > {children} </Link> ); }, ); const routes = [ { name: 'home', path: '', exact: true, component: () => <div>Home page component</div>, }, ]; function App() { return ( <AppProvider routerLinkComponent={MyRouterLinkComponent}> <Router routes={routes}> <RouteComponent /> </Router> </AppProvider> ); }
Was this page helpful?
We use this feedback to improve our documentation.
© 2026 AtlassianTrademark, (opens new window)Privacy, (opens new window)License