Skip to content
Theme UI
GitHub

Color Modes

Color modes can be used to create a user-configurable dark mode or any number of other color modes.

Defining colors

In the theme.colors object, add a nested modes object that will contain keys for optional color modes.

// example theme colors
{
initialColorModeName: 'light',
colors: {
text: '#000',
background: '#fff',
primary: '#07c',
modes: {
dark: {
text: '#fff',
background: '#000',
primary: '#0cf',
}
}
}
}

All colors found in colors.modes will be referenced by their key in the context object rawColors.modes. The above example will have two modes: light and dark.

Initial colors

The colors defined at the root of the colors are swapped out whenever the color mode changes change. This is to allow for reference like theme.colors.primary to return:

  • colors.primary, when the color mode is set to its initial mode
  • colors.modes.dark.primary, when the color mode is set to dark

Because of this, we store those initial colors with the other modes. They will be accessible as

  • rawColors.modes.__default (if initialColorModeName is undefined)
  • rawColors.modes.light (using the value of initialColorModeName).
{
initialColorModeName: 'light',
rawColors: {
primary: '#07c',
modes: {
// __default: {}, no '__default' here as initialColorModeName is defined
light: { primary: '#07c' },
dark: { primary: '#0cf' }
}
}
}

Colors Object

The colors object contains Custom CSS Properties

{
colors: {
text: 'var(--theme-ui-colors-text)',
background: 'var(--theme-ui-colors-background)',
primary: 'var(--theme-ui-colors-primary)',
}
}

rawColors Object

If you need to pass original value somewhere where CSS Properties (e.g. WebGL Canvas) won't work, use rawColors

{
rawColors: {
text: '#000',
background: '#fff',
primary: '#07c',
}
}

Use specific modes

With the sx prop

export default (props) => (
<div
sx={(theme) => ({
color: theme.rawColors.modes?.dark?.text
bg: theme.rawColors.modes?.dark?.bg
})}
/>
)

With Theme UI context

Use the useThemeUI hook to access the context object directly in a component.

import { useThemeUI } from 'theme-ui'
export default (props) => {
const { theme: { rawColors }, setColorMode } = useThemeUI()
return Object.entries(rawColors?.modes).map(([mode, values]) => ({
<Button
sx={{ bg: values.background, color: values.text }}
onClick={() => setColorMode(mode)}
>
{mode}
</Button>
}))
}
// OUTPUT
<Button>light</Button>
<Button>dark</Button>
<Button>deep</Button>
// ...

Setting the color mode

Use the useColorMode hook in your application to change the color mode. This value will be stored in localStorage and used whenever the page is loaded.

import { useColorMode } from 'theme-ui'
export default (props) => {
const [colorMode, setColorMode] = useColorMode()
return (
<header>
<button
onClick={(e) => {
setColorMode(colorMode === 'default' ? 'dark' : 'default')
}}>
Toggle {colorMode === 'default' ? 'Dark' : 'Light'}
</button>
</header>
)
}

Applying colors

The ThemeProvider component will automatically apply color mode styles to the <html> element.

import { ThemeProvider } from 'theme-ui'
import theme from './theme'
export default (props) => (
<ThemeProvider theme={theme}>{props.children}</ThemeProvider>
)
  • To disable this behavior, add the useRootStyles: false flag to your theme.

Gatsby plugin

For use in a Gatsby site, install and use gatsby-plugin-theme-ui to add the ThemeProvider to the root of your application. The plugin will also help prevent the flash of colors that can happen during page load when a user has a non-default color mode set.

npm i gatsby-plugin-theme-ui

This plugin will look for a src/gatsby-plugin-theme-ui/index.js file to import and pass to the ThemeProvider.

gatsby-config.js
module.exports = {
plugins: ['gatsby-plugin-theme-ui'],
}

See the Gatsby plugin docs for more info.

Advanced

Theme UI includes a few advanced configuration options for color modes.

Turn off custom properties

Theme UI uses CSS custom properties under the hood to help prevent the flash of color on load. If you’re targeting browsers that don't support custom properties you can turn off this setting. This will cause the colors to flash on initial page load.

// example theme colors
{
config: {
useCustomProperties: false,
},
colors: {
text: '#000',
background: '#fff',
primary: '#07c',
modes: {
dark: {
text: '#fff',
background: '#000',
primary: '#0cf',
}
}
}
}

Responding to the prefers-color-scheme media query

The useColorSchemeMediaQuery option on the theme configuration initializes a color mode based on the prefers-color-scheme media query. This will set the initial color mode to dark when @media (prefers-color-scheme: dark) matches, or light when @media (prefers-color-scheme: light) matches. If you do not have a color mode named dark or light, this will have no effect. This is enabled by default.

{
config: {
useColorSchemeMediaQuery: false,
},
colors: {
text: '#000',
background: '#fff',
modes: {
dark: {
text: '#fff',
background: '#000',
}
}
}
}

Disable persisting color mode on localStorage

To disable localStorage, add the useLocalStorage: false flag to your theme configuration.

{
config: {
useLocalStorage: false
},
colors: {
text: '#000',
background: '#fff',
modes: {
dark: {
text: '#fff',
background: '#000',
}
}
}
}

Set a custom color mode for printing

By default, when printing a webpage, browsers will use the current color mode enabled. (This means if a user is currently using a dark or colored-background mode, their printed page will share that styling). If you’d like to set a color mode to be used on printing, set that color mode with the configuration option printColorModeName, set to one of your colors.modes names, the initialColorModeName value, or the string 'initial'.

This option sets your color mode in the @media print media query, so there’s no additional client-side JavaScript for printing.

{
config: {
initialColorModeName: 'light',
printColorModeName: 'light',
},
colors: {
text: '#000',
background: '#fff',
modes: {
dark: {
text: '#fff',
background: '#000',
}
}
}
}
Edit the page on GitHub
Previous:
Styling MDX
Next:
Themed