Overview
The useColorMode hook provides access to the current color mode state and a function to update it. It must be used within a ColorModeProvider component.
Import
import { useColorMode } from 'theme-ui'
Signature
function useColorMode<T extends string = string>(): [
T,
Dispatch<SetStateAction<T>>
]
Return Value
Returns a tuple with two elements:
The current color mode name (e.g., 'light', 'dark', or a custom mode name)
[1]
Dispatch<SetStateAction<string>>
required
A function to update the color mode. Accepts either a color mode name string or a function that receives the current mode and returns the new mode.
Usage
Basic Example
import { useColorMode } from 'theme-ui'
function ColorModeToggle() {
const [colorMode, setColorMode] = useColorMode()
return (
<button
onClick={() => {
setColorMode(colorMode === 'light' ? 'dark' : 'light')
}}
>
{colorMode === 'light' ? 'Dark' : 'Light'}
</button>
)
}
With Type Safety
You can specify a narrower type for your color mode names:
type ColorMode = 'light' | 'dark' | 'sepia'
function ColorModeToggle() {
const [colorMode, setColorMode] = useColorMode<ColorMode>()
return (
<select
value={colorMode}
onChange={(e) => setColorMode(e.target.value as ColorMode)}
>
<option value="light">Light</option>
<option value="dark">Dark</option>
<option value="sepia">Sepia</option>
</select>
)
}
With Functional Updates
function toggleColorMode() {
const [colorMode, setColorMode] = useColorMode()
const toggle = () => {
setColorMode((prevMode) => {
if (prevMode === 'light') return 'dark'
if (prevMode === 'dark') return 'sepia'
return 'light'
})
}
return <button onClick={toggle}>Toggle</button>
}
Configuration
The behavior of useColorMode is controlled by settings in your theme configuration:
export default {
config: {
// Set the initial color mode (default)
initialColorModeName: 'light',
// Enable/disable localStorage persistence
useLocalStorage: true,
// Use system color scheme preference
// false: disabled
// true: only on initial load
// 'system': always follow system preference
useColorSchemeMediaQuery: true,
},
colors: {
text: '#000',
background: '#fff',
modes: {
dark: {
text: '#fff',
background: '#000',
},
},
},
}
Configuration Options
config.initialColorModeName
The default color mode to use. Should be a unique name and not reference a key in theme.colors.modes.
Whether to persist the color mode selection in localStorage.
config.useColorSchemeMediaQuery
boolean | 'system'
default:true
Controls system color scheme integration:
false: Disabled
true: Use system preference on initial load only
'system': Always follow system preference (overrides user selection)
Error Handling
useColorMode throws an error if called outside of a ColorModeProvider. Make sure your component tree is wrapped with ColorModeProvider or use the main ThemeProvider from theme-ui which includes color mode support.
// ❌ This will throw an error
function App() {
const [colorMode, setColorMode] = useColorMode() // Error!
return <div>...</div>
}
// ✅ This works
import { ThemeProvider } from 'theme-ui'
import theme from './theme'
function App() {
return (
<ThemeProvider theme={theme}>
<MyComponent />
</ThemeProvider>
)
}
function MyComponent() {
const [colorMode, setColorMode] = useColorMode() // Works!
return <div>...</div>
}
Notes
- Color mode changes are automatically persisted to localStorage (unless disabled)
- The selected color mode is stored with the key
theme-ui-color-mode
- If localStorage is disabled in the browser, a warning will be logged to the console
- When
useColorSchemeMediaQuery is set to 'system', the hook will automatically update when the system color scheme changes