CSS theme variables - Configuration
A guide for configuring CSS theme variables in Material UI.
Customizing variable prefix
To change the default variable prefix (--mui
), provide a string to cssVarPrefix
property, as shown below:
createTheme({ cssVariables: { cssVarPrefix: 'any' } });
// generated stylesheet:
// --any-palette-primary-main: ...;
To remove the prefix, use an empty string as a value:
createTheme({ cssVariables: { cssVarPrefix: '' } });
// generated stylesheet:
// --palette-primary-main: ...;
Toggling dark mode manually
To toggle between modes manually, set the colorSchemeSelector
with one of the following selectors:
createTheme({
colorSchemes: { light: true, dark: true },
cssVariables: {
colorSchemeSelector: 'class'
}
});
// CSS Result
.light { ... }
.dark { ... }
Then, use useColorScheme
hook to switch between modes:
import { useColorScheme } from '@mui/material/styles';
function ModeSwitcher() {
const { mode, setMode } = useColorScheme();
if (!mode) {
return null;
}
return (
<select
value={mode}
onChange={(event) => {
setMode(event.target.value);
// For TypeScript, cast `event.target.value as 'light' | 'dark' | 'system'`:
}}
>
<option value="system">System</option>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
);
}
Determining the system mode
To determine if the system mode is light
or dark
, use the systemMode
property:
const { mode, systemMode } = useColorScheme();
console.log(mode); // 'system'
console.log(systemMode); // 'light' | 'dark'
However, if the mode is not system
, the systemMode
will be undefined
.
const { mode, systemMode } = useColorScheme();
console.log(mode); // 'light' | 'dark'
console.log(systemMode); // undefined
Preventing SSR flickering
For SSR (server-side rendering) applications, Material UI can not detected user-selected mode on the server, causing the screen to flicker from light to dark during the hydration phase on the client.
To prevent the issue, you need to ensure that there is no usage of theme.palette.mode === 'dark'
in your code base.
If you have such a condition, replace it with the theme.applyStyles()
function:
import Card from '@mui/material/Card';
function App() {
return (
<Card
- sx={(theme) => ({
- backgroundColor: theme.palette.mode === 'dark' ? '#000' : '#fff',
- '&:hover': {
- backgroundColor: theme.palette.mode === 'dark' ? '#333' : '#f5f5f5',
- },
- })}
+ sx={[
+ {
+ backgroundColor: '#fff',
+ '&:hover': {
+ backgroundColor: '#f5f5f5',
+ },
+ },
+ (theme) =>
+ theme.applyStyles('dark', {
+ backgroundColor: '#000',
+ '&:hover': {
+ backgroundColor: '#333',
+ },
+ }),
+ ]}
/>
);
}
Next, if you have a custom selector that is not media
, add the InitColorSchemeScript
component based on the framework that you are using:
Next.js App Router
Add the following code to the root layout file:
import InitColorSchemeScript from '@mui/material/InitColorSchemeScript';
export default function RootLayout(props) {
return (
<html lang="en" suppressHydrationWarning>
<body>
{/* must come before the <main> element */}
<InitColorSchemeScript attribute="class" />
<main>{children}</main>
</body>
</html>
);
}
Next.js Pages Router
Add the following code to the custom pages/_document.js
file:
import Document, { Html, Head, Main, NextScript } from 'next/document';
import InitColorSchemeScript from '@mui/material/InitColorSchemeScript';
export default class MyDocument extends Document {
render() {
return (
<Html>
<Head>...</Head>
<body>
{/* must come before the <Main> element */}
<InitColorSchemeScript attribute="class" />
<Main />
<NextScript />
</body>
</Html>
);
}
}
Gatsby
Place the script in your gatsby-ssr.js
file:
import * as React from 'react';
import InitColorSchemeScript from '@mui/material/InitColorSchemeScript';
export function onRenderBody({ setPreBodyComponents }) {
setPreBodyComponents([<InitColorSchemeScript attribute="class" />]);
}
Forcing a specific color scheme
To force a specific color scheme for some part of your application, set the selector to the component or HTML element directly.
In the example below, all the components inside the div
will always be dark:
// if the selector is '.mode-%s'
<div className=".mode-dark">
<Paper sx={{ p: 2 }}>
<TextField label="Email" type="email" margin="normal" />
<TextField label="Password" type="password" margin="normal" />
<Button>Sign in</Button>
</Paper>
{/* other components */}
</div>
Disabling CSS color scheme
By default, createTheme()
attaches a CSS color-scheme
property based on the palette mode.
You can disable this by setting disableCssColorScheme
to true
:
createTheme({
cssVariables: { disableCssColorScheme: true },
});
The generated CSS will not include the color-scheme
property:
@media (prefers-color-scheme: dark) {
:root {
- color-scheme: dark;
--mui-palette-primary-main: #90caf9;
...
}
}
Instant transition between color schemes
To disable CSS transitions when switching between modes, apply the disableTransitionOnChange
prop:
<ThemeProvider disableTransitionOnChange />