Dark mode
MUI comes with two palette modes: light (the default) and dark.
You can make the theme dark by setting mode: 'dark'
.
const darkTheme = createTheme({
palette: {
mode: 'dark',
},
});
While it's only a single value change, the createTheme
helper modifies several palette values.
The colors modified by the palette mode are the following:
Typography
palette.text.primary
#fff
palette.text.secondary
rgba(255, 255, 255, 0.7)
palette.text.disabled
rgba(255, 255, 255, 0.5)
Buttons
palette.action.active
#fff
palette.action.hover
rgba(255, 255, 255, 0.08)
palette.action.selected
rgba(255, 255, 255, 0.16)
palette.action.disabled
rgba(255, 255, 255, 0.3)
palette.action.disabledBackground
rgba(255, 255, 255, 0.12)
Background
palette.background.default
#121212
palette.background.paper
#121212
Divider
palette.divider
rgba(255, 255, 255, 0.12)
Typography
palette.text.primary
rgba(0, 0, 0, 0.87)
palette.text.secondary
rgba(0, 0, 0, 0.6)
palette.text.disabled
rgba(0, 0, 0, 0.38)
Buttons
palette.action.active
rgba(0, 0, 0, 0.54)
palette.action.hover
rgba(0, 0, 0, 0.04)
palette.action.selected
rgba(0, 0, 0, 0.08)
palette.action.disabled
rgba(0, 0, 0, 0.26)
palette.action.disabledBackground
rgba(0, 0, 0, 0.12)
Background
palette.background.default
#fff
palette.background.paper
#fff
Divider
palette.divider
rgba(0, 0, 0, 0.12)
Note: The colors are modified only if you use the default palette. If you have a custom palette, you need to make sure that you have the correct values based on the
mode
. The following section explains how you can do it.
Dark mode with custom palette
The easiest way of how you can implement your custom palette that depends on mode is to have a dedicated function that will return the palette based on the mode. For example:
const getDesignTokens = (mode: PaletteMode) => ({
palette: {
mode,
...(mode === 'light'
? {
// palette values for light mode
primary: amber,
divider: amber[200],
text: {
primary: grey[900],
secondary: grey[800],
},
}
: {
// palette values for dark mode
primary: deepOrange,
divider: deepOrange[700],
background: {
default: deepOrange[900],
paper: deepOrange[900],
},
text: {
primary: '#fff',
secondary: grey[500],
},
}),
},
});
You can see on the example that there are different colors used based on whether the mode is light or dark. The next step is to use this function when creating the theme.
export default function App() {
const [mode, setMode] = React.useState<PaletteMode>('light');
const colorMode = React.useMemo(
() => ({
// The dark mode switch would invoke this method
toggleColorMode: () => {
setMode((prevMode: PaletteMode) =>
prevMode === 'light' ? 'dark' : 'light',
);
},
}),
[],
);
// Update the theme only if the mode changes
const theme = React.useMemo(() => createTheme(getDesignTokens(mode)), [mode]);
return (
<ColorModeContext.Provider value={colorMode}>
<ThemeProvider theme={theme}>
<Page />
</ThemeProvider>
</ColorModeContext.Provider>
);
}
Here is a fully working example:
System preference
Users might have specified a preference for a light or dark theme. The method by which the user expresses their preference can vary. It might be a system-wide setting exposed by the Operating System, or a setting controlled by the User Agent.
You can leverage this preference dynamically with the useMediaQuery hook and the prefers-color-scheme media query.
For instance, you can enable the dark mode automatically:
import * as React from 'react';
import useMediaQuery from '@mui/material/useMediaQuery';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
function App() {
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
const theme = React.useMemo(
() =>
createTheme({
palette: {
mode: prefersDarkMode ? 'dark' : 'light',
},
}),
[prefersDarkMode],
);
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Routes />
</ThemeProvider>
);
}