Endurative

How to Implement Scalable Dark Mode in Material UI (MUI) — A Complete Guide for 2025

If you’ve tried adding dark mode to a React + Material UI (MUI) application by just toggling a CSS class, you’ve probably run into styling inconsistencies, performance issues, and a mess of hardcoded colors.

In this guide, we’ll walk through a structured, scalable, and reusable way to implement dark mode in MUI — perfect for growing applications in 2025.

Common Pitfalls Developers Face with Dark Mode in React

1. Scalability Issues with Inline Styling

When an application grows, sprinkling sx={{ color: "#fff" }} everywhere creates a nightmare for maintainability.

2. Inconsistent Styling Across Components

Components like Table, TextField, and AppBar won’t automatically adapt to dark mode unless they’re tied into MUI’s theming system.

3. Managing Custom Colors Effectively.

While MUI provides light and dark palette modes, your brand colors often need to work in both modes — requiring a clear structure.

The Scalable Solution: Centralized MUI Dark Mode Setup

The key is to centralize theming so your application adapts automatically when the mode changes.

Step 1 — Install MUI Packages

npm install @mui/material @emotion/react @emotion/styled @mui/icons-material

Step 2— Centralize Colors in theme/colors.ts

export const brandColors = {
primary: {
light: '#42A5F5',
main: '#1E88E5',
dark: '#1565C0',
},
secondary: {
light: '#FFB74D',
main: '#FF9800',
dark: '#F57C00',
},
};

This ensures all brand colors live in one file, preventing duplication.

Step 3— Create a Theme Factory in theme/createAppTheme.ts

This function generates your MUI theme based on the selected mode.

import { createTheme } from '@mui/material/styles';
import { brandColors } from './colors';

export const createAppTheme = (mode: 'light' | 'dark') =>
createTheme({
palette: {
mode,
primary: brandColors.primary,
secondary: brandColors.secondary,
background: mode === 'dark'
? { default: '#121212', paper: '#1E1E1E' }
: { default: '#F5F5F5', paper: '#FFFFFF' },
},
typography: {
fontFamily: `'Inter', sans-serif`,
},
components: {
MuiCssBaseline: {
styleOverrides: {
body: { backgroundColor: mode === 'dark' ? '#121212' : '#fff' },
},
},
MuiPaper: {
styleOverrides: {
root: ({ theme }) => ({
backgroundColor: theme.palette.background.paper,
backgroundImage: 'none',
}),
},
},
},
});

Step 4— Add a Theme Context Provider

import React, { createContext, useContext, useMemo, useState } from 'react';
import { ThemeProvider, CssBaseline, StyledEngineProvider } from '@mui/material';
import { createAppTheme } from '../theme/createAppTheme';

const ThemeModeContext = createContext({ toggleMode: () => {}, mode: 'light' });

export const useThemeMode = () => useContext(ThemeModeContext);

export const ThemeModeProvider = ({ children }) => {
const [mode, setMode] = useState(() => localStorage.getItem('themeMode') || 'light');
const theme = useMemo(() => createAppTheme(mode), [mode]);

const toggleMode = () => {
setMode(prev => {
const next = prev === 'light' ? 'dark' : 'light';
localStorage.setItem('themeMode', next);
return next;
});
};

return (
<StyledEngineProvider injectFirst>
<ThemeModeContext.Provider value={{ toggleMode, mode }}>
<ThemeProvider theme={theme}>
<CssBaseline />
{children}
</ThemeProvider>
</ThemeModeContext.Provider>
</StyledEngineProvider>
);
};

Step 5— Implement a Dark Mode Toggle Component

import { AppBar, Toolbar, IconButton, Typography, Tooltip } from '@mui/material';
import { DarkModeOutlined, LightModeOutlined } from '@mui/icons-material';
import { useTheme } from '@mui/material/styles';
import { useThemeMode } from '../context/ThemeContext';

export default function AppHeader() {
const theme = useTheme();
const { toggleMode } = useThemeMode();

return (
<AppBar position="static" color="transparent" elevation={0}>
<Toolbar>
<Typography variant="h6" sx={{ flexGrow: 1 }}>Dark Mode Demo</Typography>
<Tooltip title={`Switch to ${theme.palette.mode === 'dark' ? 'Light' : 'Dark'} Mode`}>
<IconButton onClick={toggleMode} color="inherit">
{theme.palette.mode === 'dark' ? <LightModeOutlined /> : <DarkModeOutlined />}
</IconButton>
</Tooltip>
</Toolbar>
</AppBar>
);
}

Best Practices for Scalable Theming in MUI

  1. Centralize colors in one file.
  2. Avoid inline objects to reduce re-renders.
  3. Use <CssBaseline /> for browser consistency.
  4. Override components globally in the theme instead of per-component styling.