Color schemes

MantineProvider manages color scheme context in your application. You can configure the default color scheme value with defaultColorScheme prop, possible values are light, dark and auto (system color scheme is used). The default value is light.

import { MantineProvider } from '@mantine/core';

function Demo() {
  return (
    <MantineProvider defaultColorScheme="dark">
      <App />
    </MantineProvider>
  );
}

data-mantine-color-scheme attribute

When MantineProvider is mounted, it sets data-mantine-color-scheme attribute on <html /> element to the value that the user has selected previously or to the value of defaultColorScheme prop. data-mantine-color-scheme attribute is used in all components styles to determine which colors should component use.

use-mantine-color-scheme hook

useMantineColorScheme hook can be used to get and set current color scheme value:

function useMantineColorScheme(): {
  /** Current color scheme value */
  colorScheme: 'dark' | 'light' | 'auto';

  /** Sets colors scheme to given value */
  setColorScheme: (colorScheme: 'dark' | 'light' | 'auto') => void;

  /** Toggle color scheme to the opposite value, if value is 'auto', color scheme is inferred from the OS settings */
  toggleColorScheme: () => void;

  /** Clears color scheme value from storage and sets it to `defaultColorScheme` */
  clearColorScheme: () => void;
};
import { useMantineColorScheme, Button, Group } from '@mantine/core';

function Demo() {
  const { setColorScheme, clearColorScheme } = useMantineColorScheme();

  return (
    <Group>
      <Button onClick={() => setColorScheme('light')}>Light</Button>
      <Button onClick={() => setColorScheme('dark')}>Dark</Button>
      <Button onClick={() => setColorScheme('auto')}>Auto</Button>
      <Button onClick={clearColorScheme}>Clear</Button>
    </Group>
  );
}

use-computed-color-scheme hook

useComputedColorScheme returns a computed color scheme value, it returns either light or dark. It can be used to implement color scheme toggle logic:

import { useComputedColorScheme, useMantineColorScheme } from '@mantine/core';

function Demo() {
  // -> colorScheme is 'auto' | 'light' | 'dark'
  const { colorScheme, setColorScheme } = useMantineColorScheme();

  // -> computedColorScheme is 'light' | 'dark', argument is the default value
  const computedColorScheme = useComputedColorScheme('light');

  // Incorrect color scheme toggle implementation
  // If colorScheme is 'auto', then it is not possible to
  // change color scheme correctly in all cases:
  // 'auto' can mean both light and dark
  const toggleColorScheme = () => {
    setColorScheme(colorScheme === 'dark' ? 'light' : 'dark');
  };

  // Correct color scheme toggle implementation
  // computedColorScheme is always either 'light' or 'dark'
  const toggleColorScheme = () => {
    setColorScheme(computedColorScheme === 'dark' ? 'light' : 'dark');
  };
}

Color scheme value caveats

By default, the color scheme value is stored in local storage, and its value is saved in state before the component is mounted to avoid flash of inaccurate color scheme. This means that color scheme value can be different on client and server, as server does not have access to local storage and always uses the default value.

If you have server side rendering in your application (for example, if you use Next.js or Remix), then you cannot use colorScheme value in your application to avoid hydration issues. Instead, you can use dark and light mixins from postcss-preset-mantine to generate styles that will hide elements based on color scheme value:

import { ActionIcon, useMantineColorScheme, useComputedColorScheme } from '@mantine/core';
import { IconSun, IconMoon } from '@tabler/icons-react';
import cx from 'clsx';
import classes from './Demo.module.css';

function Demo() {
  const { setColorScheme } = useMantineColorScheme();
  const computedColorScheme = useComputedColorScheme('light', { getInitialValueInEffect: true });

  return (
    <ActionIcon
      onClick={() => setColorScheme(computedColorScheme === 'light' ? 'dark' : 'light')}
      variant="default"
      size="xl"
      aria-label="Toggle color scheme"
    >
      <IconSun className={cx(classes.icon, classes.light)} stroke={1.5} />
      <IconMoon className={cx(classes.icon, classes.dark)} stroke={1.5} />
    </ActionIcon>
  );
}

colorScheme for client only applications

You can safely use colorScheme value in client only applications (for example, Vite or create-react-app applications). In this case, there is no hydration, and thus hydration error cannot occur.

ColorSchemeScript

ColorSchemeScript component renders script tag that sets data-mantine-color-scheme attribute on <html /> element to user selected value or to defaultColorScheme prop value before hydration. It is used to avoid flash of inaccurate color scheme in server side rendered applications, for example Next.js or Remix. Follows framework specific guides to learn where to render ColorSchemeScript component.

You can add any additional props to the <script /> tag generated by ColorSchemeScript component, for example, you can add nonce attribute:

import { ColorSchemeScript } from '@mantine/core';

function Demo() {
  return <ColorSchemeScript nonce="8IBTHwOdqNKAWeKl7plt8g==" defaultColorScheme="dark" />;
}

Color scheme manager

By default, color scheme value is stored in local storage, but you can implement your own color scheme manager to store the value in any other external storage.

Color scheme manager must have the following methods:

interface MantineColorSchemeManager {
  /** Function to retrieve color scheme value from external storage, for example window.localStorage */
  get(defaultValue: MantineColorScheme): MantineColorScheme;

  /** Function to set color scheme value in external storage, for example window.localStorage */
  set(value: MantineColorScheme): void;

  /** Function to subscribe to color scheme changes triggered by external events */
  subscribe(onUpdate: (colorScheme: MantineColorScheme) => void): void;

  /** Function to unsubscribe from color scheme changes triggered by external events */
  unsubscribe(): void;

  /** Function to clear value from external storage */
  clear(): void;
}

Usually, it is better to wrap color scheme manager in a creator function to provide a way to configure it. Default local storage based color scheme manager example:

import { MantineColorScheme, MantineColorSchemeManager, isMantineColorScheme } from '@mantine/core';

export interface LocalStorageColorSchemeManagerOptions {
  /** Local storage key used to retrieve value with `localStorage.getItem(key)`, `mantine-color-scheme` by default */
  key?: string;
}

export function localStorageColorSchemeManager({
  key = 'mantine-color-scheme',
}: LocalStorageColorSchemeManagerOptions = {}): MantineColorSchemeManager {
  let handleStorageEvent: (event: StorageEvent) => void;

  return {
    get: (defaultValue) => {
      if (typeof window === 'undefined') {
        return defaultValue;
      }

      try {
        return (window.localStorage.getItem(key) as MantineColorScheme) || defaultValue;
      } catch {
        return defaultValue;
      }
    },

    set: (value) => {
      try {
        window.localStorage.setItem(key, value);
      } catch (error) {
        // eslint-disable-next-line no-console
        console.warn(
          '[@mantine/core] Local storage color scheme manager was unable to save color scheme.',
          error
        );
      }
    },

    subscribe: (onUpdate) => {
      handleStorageEvent = (event) => {
        if (event.storageArea === window.localStorage && event.key === key) {
          isMantineColorScheme(event.newValue) && onUpdate(event.newValue);
        }
      };

      window.addEventListener('storage', handleStorageEvent);
    },

    unsubscribe: () => {
      window.removeEventListener('storage', handleStorageEvent);
    },

    clear: () => {
      window.localStorage.removeItem(key);
    },
  };
}

Then custom color scheme manager can be passed to MantineProvider:

import { MantineProvider } from '@mantine/core';
import { localStorageColorSchemeManager } from './localStorageColorSchemeManager';

const colorSchemeManager = localStorageColorSchemeManager({ key: 'my-color-scheme' });

function Demo() {
  return (
    <MantineProvider colorSchemeManager={colorSchemeManager}>
      <App />
    </MantineProvider>
  );
}

Default color scheme

The default color scheme value is used when the user has not selected any color scheme yet. It is required to be set both on MantineProvider and ColorSchemeScript. If defaultColorScheme is not set, then light is used – your application color scheme will depend on the system color scheme.

import { MantineProvider, ColorSchemeScript } from '@mantine/core';

function Demo() {
  return (
    <>
      <ColorSchemeScript defaultColorScheme="dark" />
      <MantineProvider defaultColorScheme="dark">
        <App />
      </MantineProvider>
    </>
  );
}

Force color scheme

You can force the color scheme value to be either light or dark with forceColorScheme prop. It is required to be set both on MantineProvider and ColorSchemeScript. If forceColorScheme is set, then defaultColorScheme and colorSchemeManager are ignored. When forceColorScheme is set, it is not possible to change color scheme value with setColorScheme function.

import { MantineProvider, ColorSchemeScript } from '@mantine/core';

function Demo() {
  return (
    <>
      <ColorSchemeScript forceColorScheme="light" />
      <MantineProvider forceColorScheme="light">
        <App />
      </MantineProvider>
    </>
  );
}