CSS theme variables - Usage
Learn how to use the experimental APIs to adopt CSS theme variables.
Getting started
Experimental_CssVarsProvider
is a provider that generates CSS theme variables and attaches a reference to the theme object (a React context).
import { Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material/styles';
function App() {
return <CssVarsProvider>...</CssVarsProvider>;
}
Once the App
renders on the screen, you will see the CSS theme variables in the html :root
stylesheet.
The variables are flattened and prefixed with --mui
by default:
/* generated global stylesheet */
:root {
--mui-palette-primary-main: #1976d2;
--mui-palette-primary-light: #42a5f5;
--mui-palette-primary-dark: #1565c0;
--mui-palette-primary-contrastText: #fff;
/* ...other variables */
}
Toggle between light and dark mode
The useColorScheme
hook lets you read and update the user-selected mode:
import {
Experimental_CssVarsProvider as CssVarsProvider,
useColorScheme,
} from '@mui/material/styles';
// ModeSwitcher is an example interface for toggling between modes.
// Material UI does not provide the toggle interface—you have to build it yourself.
const ModeSwitcher = () => {
const { mode, setMode } = useColorScheme();
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
// for server-side rendering
// learn more at https://github.com/pacocoursey/next-themes#avoid-hydration-mismatch
return null;
}
return (
<Button
variant="outlined"
onClick={() => {
if (mode === 'light') {
setMode('dark');
} else {
setMode('light');
}
}}
>
{mode === 'light' ? 'Dark' : 'Light'}
</Button>
);
};
function App() {
return (
<CssVarsProvider>
<ModeSwitcher />
</CssVarsProvider>
);
}
Using theme variables
theme.vars
(recommended): an object that refers to the CSS theme variables.const Button = styled('button')(({ theme }) => ({ backgroundColor: theme.vars.palette.primary.main, // var(--mui-palette-primary-main) color: theme.vars.palette.primary.contrastText, // var(--mui-palette-primary-contrastText) }));
For TypeScript, the typings are not enabled by default. Follow the TypeScript setup to enable the typings.
Native CSS: if you can't access the theme object, e.g. in a pure CSS file, you can use
var()
directly:/* external-scope.css */ .external-section { background-color: var(--mui-palette-grey-50); }
Server-side rendering
Place getInitColorSchemeScript()
before the <Main />
tag to prevent the dark-mode SSR flickering during the hydration phase.
Next.js
Add the following code to the custom pages/_document.js
file:
import Document, { Html, Head, Main, NextScript } from 'next/document';
import { getInitColorSchemeScript } from '@mui/material/styles';
export default class MyDocument extends Document {
render() {
return (
<Html>
<Head>...</Head>
<body>
{getInitColorSchemeScript()}
<Main />
<NextScript />
</body>
</Html>
);
}
}
Gatsby
Add the following code to the custom gatsby-ssr.js
file:
import React from 'react';
import { getInitColorSchemeScript } from '@mui/material/styles';
export function onRenderBody({ setPreBodyComponents }) {
setPreBodyComponents([getInitColorSchemeScript()]);
}
TypeScript
The theme variables type is not enabled by default. You need to import the module augmentation to enable the typings:
// The import can be in any file that is included in your `tsconfig.json`
import type {} from '@mui/material/themeCssVarsAugmentation';
import { styled } from '@mui/material/styles';
const StyledComponent = styled('button')(({ theme }) => ({
// ✅ typed-safe
color: theme.vars.palette.primary.main,
}));