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{config: {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 modecolors.modes.dark.primary
, when the color mode is set todark
Because of this, we store those initial colors with the other modes. They will be accessible as
rawColors.modes.__default
(ifinitialColorModeName
is undefined)rawColors.modes.light
(using the value ofinitialColorModeName
).
{config: {initialColorModeName: 'light',}rawColors: {primary: '#07c',modes: {// __default: {}, no '__default' here as initialColorModeName is definedlight: { 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) => (<divsx={(theme) => ({color: theme.rawColors.modes?.dark?.textbg: 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]) => ({<Buttonsx={{ 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><buttononClick={(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.
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',}}}}
- To enable the color mode to update when a user's current
prefers-color-scheme
media query value changes, setuseColorSchemeMediaQuery
to'system'
.
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.
Edit the page on GitHub{config: {initialColorModeName: 'light',printColorModeName: 'light',},colors: {text: '#000',background: '#fff',modes: {dark: {text: '#fff',background: '#000',}}}}