Skip to content

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,
}));