
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:
- Poor contrast
- Problem: Brand colors often fail WCAG contrast standards.
- Solution: Test palettes using WebAIM Contrast Checker.
- Semantic confusion
- Problem: Some palettes use color alone to indicate state (e.g., errors).
- Solution: Use icons, labels, or patterns in addition to color.
- 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.