Skip to content

CSS theme variables

An overview of adopting CSS theme variables in Material UI.

CSS variables are a modern cross-browser feature that let you declare variables in CSS and reuse them in other properties. You can implement them to improve Material UI's theming and customization experience.

Introduction

CSS theme variable support is a new feature in Material UI added in v5.6.0 (but not enabled by default). It tells Material UI components to use the generated CSS theme variables instead of raw values. This provides significant improvements in developer experience related to theming and customization. With these variables, you can inject a theme into your app's stylesheet at build time to apply the user's selected settings before the whole app is rendered.

Advantages

  • It lets you prevent dark-mode SSR flickering.
  • You can create unlimited color schemes beyond light and dark.
  • It offers a better debugging experience not only for developers but also designers on your team.
  • The color scheme of your website is automatically synced between browser tabs.
  • It simplifies integration with third-party tools because CSS theme variables are available globally.
  • It reduces the need for a nested theme when you want to apply dark styles to a specific part of your application.

Trade-offs

For server-side applications, there are some trade-offs to consider:

Compare to the default method Reason
HTML size Bigger CSS variables are generated for both light and dark mode at build time.
First Contentful Paint (FCP) Larger Since the HTML size is generally bigger, the time to download the HTML before showing the content is longer.
Time to Interactive (TTI) Smaller (for dark mode) Stylesheets are not regenerated between light and dark mode, so it takes less time for JavaScript to run.

Mental model

Adopting CSS variables requires some shifts in your mental model of theming and customizing user-selected modes.

Colors

Default approach: Light and dark colors are created separately.

<span class="token keyword">const</span> lightTheme <span class="token operator">=</span> <span class="token function">createTheme</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> darkTheme <span class="token operator">=</span> <span class="token function">createTheme</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">palette</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">'dark'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

CSS theme variables: Light and dark colors are consolidated into a theme.

<span class="token comment">// `extendTheme` is a new API</span>
<span class="token keyword">const</span> theme <span class="token operator">=</span> <span class="token function">extendTheme</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">colorSchemes</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">light</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token comment">// palette for light mode</span>
      <span class="token literal-property property">palette</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token operator">...</span><span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">dark</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token comment">// palette for dark mode</span>
      <span class="token literal-property property">palette</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token operator">...</span><span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

Styling

Default approach: Usually relies on JavaScript to switch the value between modes:

<span class="token function">createTheme</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">MuiButton</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">styleOverrides</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token function-variable function">root</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> theme <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
          <span class="token comment">// use JavaScript conditional expression</span>
          <span class="token literal-property property">color</span><span class="token operator">:</span> theme<span class="token punctuation">.</span>palette<span class="token punctuation">.</span>mode <span class="token operator">===</span> <span class="token string">'dark'</span> <span class="token operator">?</span> <span class="token string">'#fff'</span> <span class="token operator">:</span> theme<span class="token punctuation">.</span>palette<span class="token punctuation">.</span>primary<span class="token punctuation">.</span>main<span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

CSS theme variables: Styling leans toward cascading and specificity by using the appropriate selector which lets you prevent dark-mode SSR flickering:

<span class="token function">extendTheme</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">MuiButton</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">styleOverrides</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token function-variable function">root</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> theme <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
          <span class="token literal-property property">color</span><span class="token operator">:</span> theme<span class="token punctuation">.</span>vars<span class="token punctuation">.</span>palette<span class="token punctuation">.</span>primary<span class="token punctuation">.</span>main<span class="token punctuation">,</span>
          <span class="token comment">// When the mode switches to dark, the attribute selector is attached to</span>
          <span class="token comment">// the &lt;html> tag by default.</span>
          <span class="token string-property property">'[data-mui-color-scheme="dark"] &amp;'</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">color</span><span class="token operator">:</span> <span class="token string">'#fff'</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

What's next