Dark mode
Learn about the different methods for applying dark mode to a Joy UI app.
Set as default
To set dark mode as the default for your app, add defaultMode: 'dark'
to your <CssVarsProvider>
wrapper component:
For server-side applications, check out the framework setup in the section below and provide the same value to the getInitColorSchemeScript
function:
<span class="token function">getInitColorSchemeScript</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">defaultMode</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>
Matching device's preference
Use defaultMode: 'system'
to set your app's default mode to match the user's chosen preference on their device.
<span class="token keyword">import</span> <span class="token punctuation">{</span> CssVarsProvider <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@mui/joy/styles'</span><span class="token punctuation">;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">CssVarsProvider</span></span> <span class="token attr-name">defaultMode</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>system<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token operator">...</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">CssVarsProvider</span></span><span class="token punctuation">></span></span><span class="token punctuation">;</span>
For server-side applications, check out the framework setup in the section below and provide the same value to the getInitColorSchemeScript
function:
<span class="token function">getInitColorSchemeScript</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">defaultMode</span><span class="token operator">:</span> <span class="token string">'system'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Identify the system mode
Use the useColorScheme
React hook to check if the user's preference is in light or dark mode:
<span class="token keyword">import</span> <span class="token punctuation">{</span> useColorScheme <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@mui/joy/styles'</span><span class="token punctuation">;</span>
<span class="token keyword">function</span> <span class="token function">SomeComponent</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> mode<span class="token punctuation">,</span> systemMode <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useColorScheme</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>mode<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "system"</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>systemMode<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// "light" | "dark" based on the user's preference.</span>
<span class="token punctuation">}</span>
Creating a mode-toggle component
You can create a toggle component to give users the option to select between modes.
In the example below, we're using a Button
component that calls setMode
from the useColorSchemes()
hook to handle the mode toggling.
<span class="token keyword">import</span> <span class="token punctuation">{</span> useColorScheme <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@mui/joy/styles'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> Button <span class="token keyword">from</span> <span class="token string">'@mui/joy/Button'</span><span class="token punctuation">;</span>
<span class="token keyword">function</span> <span class="token function">ModeToggle</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> mode<span class="token punctuation">,</span> setMode <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useColorScheme</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Button</span></span>
<span class="token attr-name">variant</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>outlined<span class="token punctuation">"</span></span>
<span class="token attr-name">color</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>neutral<span class="token punctuation">"</span></span>
<span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setMode</span><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">'light'</span> <span class="token operator">:</span> <span class="token string">'dark'</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span>
<span class="token punctuation">></span></span>
<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">'Turn light'</span> <span class="token operator">:</span> <span class="token string">'Turn dark'</span><span class="token punctuation">}</span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">Button</span></span><span class="token punctuation">></span></span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
Server-side rendering notes
Avoid hydration mismatch
Make sure to render the UI when the page is mounted on the client.
This is because the mode
will only be available to the client-side (it is undefined
on the server).
If you try to render your UI based on the server, before mounting on the client, you'll see a hydration mismatch error.
<span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line">function ModeToggle() {
</span><span class="token prefix unchanged"> </span><span class="token line"> const { mode, setMode } = useColorScheme();
</span><span class="token prefix unchanged"> </span><span class="token line"> const [mounted, setMounted] = React.useState(false);
</span></span>
<span class="token inserted-sign inserted"><span class="token prefix inserted">+</span><span class="token line"> React.useEffect(() => {
</span><span class="token prefix inserted">+</span><span class="token line"> setMounted(true);
</span><span class="token prefix inserted">+</span><span class="token line"> }, []);
</span><span class="token prefix inserted">+</span><span class="token line">
</span><span class="token prefix inserted">+</span><span class="token line"> if (!mounted) {
</span><span class="token prefix inserted">+</span><span class="token line"> // to avoid layout shift, render a placeholder button
</span><span class="token prefix inserted">+</span><span class="token line"> return <Button variant="outlined" color="neutral" sx={{ width: 120 }} />;
</span><span class="token prefix inserted">+</span><span class="token line"> }
</span></span>
<span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line"> return (
</span><span class="token prefix unchanged"> </span><span class="token line"> <Button
</span><span class="token prefix unchanged"> </span><span class="token line"> variant="outlined"
</span><span class="token prefix unchanged"> </span><span class="token line"> color="neutral"
</span><span class="token prefix unchanged"> </span><span class="token line"> onClick={() => setMode(mode === 'dark' ? 'light' : 'dark')}
</span><span class="token prefix unchanged"> </span><span class="token line"> >
</span><span class="token prefix unchanged"> </span><span class="token line"> {mode === 'dark' ? 'Turn light' : 'Turn dark'}
</span><span class="token prefix unchanged"> </span><span class="token line"> </Button>
</span><span class="token prefix unchanged"> </span><span class="token line"> );
</span><span class="token prefix unchanged"> </span><span class="token line">};</span></span>
Avoiding screen flickering
To prevent the UI from flickering, apply getInitColorSchemeScript()
before the main application script-it varies across frameworks:
Next.js
To use the Joy UI API with a Next.js project, add the following code to the custom pages/_document.js
file:
<span class="token keyword">import</span> Document<span class="token punctuation">,</span> <span class="token punctuation">{</span> Html<span class="token punctuation">,</span> Head<span class="token punctuation">,</span> Main<span class="token punctuation">,</span> NextScript <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'next/document'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> getInitColorSchemeScript <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@mui/joy/styles'</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">class</span> <span class="token class-name">MyDocument</span> <span class="token keyword">extends</span> <span class="token class-name">Document</span> <span class="token punctuation">{</span>
<span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Html</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Head</span></span><span class="token punctuation">></span></span><span class="token operator">...</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">Head</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span>
<span class="token punctuation">{</span><span class="token function">getInitColorSchemeScript</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Main</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">NextScript</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">Html</span></span><span class="token punctuation">></span></span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
Gatsby
To use the Joy UI API with a Gatsby project, add the following code to the custom gatsby-ssr.js
file:
<span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> getInitColorSchemeScript <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@mui/joy/styles'</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">onRenderBody</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> setPreBodyComponents <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">setPreBodyComponents</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token function">getInitColorSchemeScript</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>