• Sep 15, 2025
  • 4 min read

Building a theme switcher with MantineUI and React: beyond dark mode

MantineUI theme switcher

Introduction

Dark mode has become a standard feature in modern web apps, but true theming goes far beyond toggling black and white backgrounds. Enterprises increasingly need multiple accessible color schemes that align with brand identity, enhance readability, and adapt to user preferences.

MantineUI, a popular React component library, offers a powerful theme system that can be extended and customized. With it, you can implement advanced theme switching that supports not only light/dark modes but also custom palettes—while maintaining accessibility compliance.

In this article, we’ll explore:

  • How Mantine’s theme system works
  • Building a theme switcher component in React
  • Extending Mantine with custom color schemes
  • Ensuring accessibility when adding new themes

By the end, you’ll have a production-ready theme switcher that elevates user experience and maintains design consistency.


1. Understanding Mantine’s theme system

Mantine provides a <MantineProvider> component that accepts a theme object. This object defines:

  • Colors: Palettes defined as arrays of shades ([50...900])
  • Primary color: The main brand accent
  • Typography: Font families, sizes, weights
  • Other tokens: Radius, spacing, shadows

Basic usage:

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

function App() {
  return (
    <MantineProvider theme={{ colorScheme: 'light' }}>
      <MyApp />
    </MantineProvider>
  );
}

Mantine supports light and dark out of the box, but we can extend this to support custom themes.

2. Building a basic theme switcher

A simple theme switcher toggles between light and dark. Mantine provides a useMantineColorScheme hook.

import { ActionIcon, useMantineColorScheme } from '@mantine/core';
import { Sun, MoonStars } from 'tabler-icons-react';

export function ThemeToggle() {
  const { colorScheme, toggleColorScheme } = useMantineColorScheme();
  const dark = colorScheme === 'dark';

  return (
    <ActionIcon
      variant="outline"
      color={dark ? 'yellow' : 'blue'}
      onClick={() => toggleColorScheme()}
      title="Toggle color scheme"
    >
      {dark ? <Sun size={16} /> : <MoonStars size={16} />}
    </ActionIcon>
  );
}

This provides a light/dark switcher—but let’s go beyond.

3. Extending Mantine with custom color schemes

To add more themes (e.g., “Corporate”, “High Contrast”), define custom color palettes.

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

const customTheme = {
  colorScheme: 'light',
  colors: {
    corporateBlue: [
      '#e6f0ff', '#b3d1ff', '#80b3ff', '#4d94ff',
      '#1a75ff', '#005ce6', '#0047b3', '#003280',
      '#001c4d', '#00091a'
    ],
    highContrast: ['#000000', '#ffffff'], // 2-value contrast scheme
  },
  primaryColor: 'corporateBlue',
};

function App() {
  return (
    <MantineProvider theme={customTheme}>
      <MyApp />
    </MantineProvider>
  );
}

Now you can switch palettes dynamically. Example of a dropdown-based switcher:

import { Select } from '@mantine/core';
import { useState } from 'react';

export function ThemeSelector({ setTheme }) {
  const [value, setValue] = useState('light');

  return (
    <Select
      label="Choose theme"
      placeholder="Pick one"
      value={value}
      onChange={(val) => {
        setValue(val);
        setTheme(val);
      }}
      data={['light', 'dark', 'corporateBlue', 'highContrast']}
    />
  );
}

4. Accessibility considerations

Adding custom themes can introduce accessibility risks. Common pitfalls:

  1. Poor contrast
  • Problem: Brand colors often fail WCAG contrast standards.
  • Solution: Test palettes using WebAIM Contrast Checker.
  1. Semantic confusion
  • Problem: Some palettes use color alone to indicate state (e.g., errors).
  • Solution: Use icons, labels, or patterns in addition to color.
  1. User preference conflicts
  • Problem: Users may have OS-level preferences (prefers-color-scheme).
  • Solution: Respect system defaults but allow overrides.

Implementation tip:

const { colorScheme, setColorScheme } = useMantineColorScheme();

// Auto-detect system preference on load
useEffect(() => {
  const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
  setColorScheme(prefersDark ? 'dark' : 'light');
}, []);

5. Pitfalls & best practices

  • Pitfall: Too many theme options → user confusion.
    • Best practice: Limit to 3–4 curated options.
  • Pitfall: Inconsistent branding across themes.
    • Best practice: Base all palettes on your design system tokens.
  • Pitfall: Theme logic scattered across app.
    • Best practice: Centralize theme management in a context or provider.

Conclusion

Dark mode alone is no longer enough. By extending MantineUI’s theme system, you can deliver multiple accessible and branded themes that improve user experience and inclusivity.

Key takeaways:

  • Mantine provides a strong base for theming via MantineProvider and hooks.
  • Advanced theme switching allows custom palettes beyond light/dark.
  • Accessibility must remain a priority—test contrast, add semantic cues, and respect user preferences.

👉 Want to integrate advanced theming systems into your React applications? Explore our UI/UX services here.

References & tools

Mantine UI React Theming UX

Related articles

Elevate your digital experience

Whether you need a custom UI design, AI-powered solutions, or expert consulting, we are here to help you bring your ideas to life with precision, creativity, and the latest in AI technology.