Dark theme

All mantine components support dark color scheme natively without any additional steps. To use dark color scheme, wrap your application in MantineProvider and specify colorScheme:

import { MantineProvider } from '@mantine/core';
function Demo() {
return (
<MantineProvider theme={{ colorScheme: 'dark' }} withGlobalStyles withNormalizeCSS>
<App />
</MantineProvider>
);
}

Colors

Mantine uses theme.colors.dark values to style components with dark color scheme:

dark 0
#C1C2C5
dark 1
#A6A7AB
dark 2
#909296
dark 3
#5c5f66
dark 4
#373A40
dark 5
#2C2E33
dark 6
#25262b
dark 7
#1A1B1E
dark 8
#141517
dark 9
#101113

You can customize these values the same way as other colors:

import { MantineProvider } from '@mantine/core';
function Demo() {
return (
<MantineProvider
withGlobalStyles
withNormalizeCSS
theme={{
colorScheme: 'dark',
colors: {
// override dark colors to change them for all components
dark: [
'#d5d7e0',
'#acaebf',
'#8c8fa3',
'#666980',
'#4d4f66',
'#34354a',
'#2b2c3d',
'#1d1e30',
'#0c0d21',
'#01010a',
],
},
}}
>
<App />
</MantineProvider>
);
}

Global styles

theme.colors.dark[7] shade is considered to be the body background color and theme.colors.dark[0] shade is used as text color with dark color scheme. You can create these styles on your own or add them by setting withGlobalStyles prop on MantineProvider, which includes them by default:

import { MantineProvider } from '@mantine/core';
function Demo() {
return (
<MantineProvider theme={{ colorScheme: 'dark' }} withGlobalStyles withNormalizeCSS>
<App />
</MantineProvider>
);
}

ColorSchemeProvider

Mantine support dynamic color scheme change and exports ColorSchemeProvider to help you set up color scheme context:

import { useState } from 'react';
import { MantineProvider, ColorSchemeProvider, ColorScheme } from '@mantine/core';
function Demo() {
const [colorScheme, setColorScheme] = useState<ColorScheme>('light');
const toggleColorScheme = (value?: ColorScheme) =>
setColorScheme(value || (colorScheme === 'dark' ? 'light' : 'dark'));
return (
<ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme}>
<MantineProvider theme={{ colorScheme }} withGlobalStyles withNormalizeCSS>
<App />
</MantineProvider>
</ColorSchemeProvider>
);
}

And then consume ColorSchemeProvider context with useMantineColorScheme hook at any place of your app:

import { ActionIcon, useMantineColorScheme } from '@mantine/core';
import { IconSun, IconMoonStars } from '@tabler/icons-react';
function Demo() {
const { colorScheme, toggleColorScheme } = useMantineColorScheme();
const dark = colorScheme === 'dark';
return (
<ActionIcon
variant="outline"
color={dark ? 'yellow' : 'blue'}
onClick={() => toggleColorScheme()}
title="Toggle color scheme"
>
{dark ? <IconSun size="1.1rem" /> : <IconMoonStars size="1.1rem" />}
</ActionIcon>
);
}

Save to localStorage and add keyboard shortcut

If you want to replicate dark theme behavior of Mantine docs website use use-local-storage hook to store theme state in localStorage and sync it across all opened tabs and use-hotkeys to add Ctrl/⌘ + J keyboard shortcut for theme toggle:

import { MantineProvider, ColorSchemeProvider, ColorScheme } from '@mantine/core';
import { useHotkeys, useLocalStorage } from '@mantine/hooks';
function Demo() {
const [colorScheme, setColorScheme] = useLocalStorage<ColorScheme>({
key: 'mantine-color-scheme',
defaultValue: 'light',
getInitialValueInEffect: true,
});
const toggleColorScheme = (value?: ColorScheme) =>
setColorScheme(value || (colorScheme === 'dark' ? 'light' : 'dark'));
useHotkeys([['mod+J', () => toggleColorScheme()]]);
return (
<ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme}>
<MantineProvider theme={{ colorScheme }} withGlobalStyles withNormalizeCSS>
<App />
</MantineProvider>
</ColorSchemeProvider>
);
}

Usually saving value to localStorage is not the best strategy as it will create FART. If it is possible, store user preferred color scheme on server and serve your application without flashes.

For example, Mantine docs are deployed to gh-pages and do not have server (website is fully static) – in this case if you refresh the page with dark theme, first you will see the prerendered light theme and your selected dark theme will be applied only after a few moments.

Detect user preferred color scheme

You can detect user preferred color scheme with media query or use-color-scheme hook and set it as default value:

import { useState } from 'react';
import { MantineProvider, ColorSchemeProvider, ColorScheme } from '@mantine/core';
import { useColorScheme } from '@mantine/hooks';
function Demo() {
// hook will return either 'dark' or 'light' on client
// and always 'light' during ssr as window.matchMedia is not available
const preferredColorScheme = useColorScheme();
const [colorScheme, setColorScheme] = useState<ColorScheme>(preferredColorScheme);
const toggleColorScheme = (value?: ColorScheme) =>
setColorScheme(value || (colorScheme === 'dark' ? 'light' : 'dark'));
return (
<ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme}>
<MantineProvider theme={{ colorScheme }} withGlobalStyles withNormalizeCSS>
<App />
</MantineProvider>
</ColorSchemeProvider>
);
}

Save color scheme in cookie

Saving color scheme in cookie is the easiest way to prevent color scheme mismatch. This strategy can be applied to any framework/library that has server side rendering support. The following example shows how to store color scheme in cookie with Next.js:

// _app.tsx file
import { useState } from 'react';
import NextApp, { AppProps, AppContext } from 'next/app';
import { getCookie, setCookie } from 'cookies-next';
import { MantineProvider, ColorScheme, ColorSchemeProvider } from '@mantine/core';
export default function App(props: AppProps & { colorScheme: ColorScheme }) {
const { Component, pageProps } = props;
const [colorScheme, setColorScheme] = useState<ColorScheme>(props.colorScheme);
const toggleColorScheme = (value?: ColorScheme) => {
const nextColorScheme = value || (colorScheme === 'dark' ? 'light' : 'dark');
setColorScheme(nextColorScheme);
// when color scheme is updated save it to cookie
setCookie('mantine-color-scheme', nextColorScheme, { maxAge: 60 * 60 * 24 * 30 });
};
return (
<ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme}>
<MantineProvider theme={{ colorScheme }} withGlobalStyles withNormalizeCSS>
<Component {...pageProps} />
</MantineProvider>
</ColorSchemeProvider>
);
}
App.getInitialProps = async (appContext: AppContext) => {
const appProps = await NextApp.getInitialProps(appContext);
return {
...appProps,
colorScheme: getCookie('mantine-color-scheme', appContext.ctx) || 'light',
};
};

Full code is available in Mantine Next.js template.