Material UI Theme Switcher for React

Here's a short post on how to create a Material-UI theme switcher for React - using React.createContext. This is based on Praveen's excellent post here... https://techinscribed.com/building-react-app-using-material-ui-with-sup…

When we're done - you should see the following React app with a simple theme toggle switcher.

Material-UI Theme Switcher

First we'll create two themes: normal.js and dark.js, and place them in a themes directory below src.

import { createMuiTheme } from '@material-ui/core/styles'
import { red } from '@material-ui/core/colors'

// Normal or default theme
const theme = createMuiTheme({
  palette: {
    primary: {
      main: '#556cd6',
    },
    secondary: {
      main: '#cc4444',
    },
    error: {
      main: red.A400,
    },
    background: {
      default: '#f5f5f5',
    },
    titleBar: {
      main: '#eeeeee',
      contrastText: '#222222',
    },
  },
})

export default theme
import { createMuiTheme } from '@material-ui/core/styles'
import { red } from '@material-ui/core/colors'

// Dark theme
const theme = createMuiTheme({
  palette: {
    type: 'dark',
    primary: {
      main: '#26292C',
      light: 'rgb(81, 91, 95)',
      dark: 'rgb(26, 35, 39)',
      contrastText: '#ffffff',
    },
    secondary: {
      main: '#FFB74D',
      light: 'rgb(255, 197, 112)',
      dark: 'rgb(200, 147, 89)',
      contrastText: 'rgba(0, 0, 0, 0.87)',
    },
    titleBar: {
      main: '#555555',
      contrastText: '#ffffff',
    },
    error: {
      main: red.A400,
    },
  },
})

export default theme

And then a simple theme switcher component - base.js also placed in the themes directory.

import normal from './normal'
import dark from './dark'

const themes = {
  normal,
  dark,
}

export default function getTheme(theme) {
  return themes[theme]
}

And now we'll create our CustomThemeProvider and React Context - CustomThemeProvider.js - also placed in the themes directory.

import React, { useState } from 'react'
import { ThemeProvider } from '@material-ui/core/styles'
import getTheme from './base'

// eslint-disable-next-line no-unused-vars
export const CustomThemeContext = React.createContext(
  {
    currentTheme: 'normal',
    setTheme: null,
  },
)

const CustomThemeProvider = (props) => {
  // eslint-disable-next-line react/prop-types
  const { children } = props

  // Read current theme from localStorage or maybe from an api
  const currentTheme = localStorage.getItem('appTheme') || 'normal'

  // State to hold the selected theme name
  const [themeName, _setThemeName] = useState(currentTheme)

  // Retrieve the theme object by theme name
  const theme = getTheme(themeName)

  // Wrap _setThemeName to store new theme names in localStorage
  const setThemeName = (name) => {
    localStorage.setItem('appTheme', name)
    _setThemeName(name)
  }

  const contextValue = {
    currentTheme: themeName,
    setTheme: setThemeName,
  }

  return (
    <CustomThemeContext.Provider value={contextValue}>
      <ThemeProvider theme={theme}>{children}</ThemeProvider>
    </CustomThemeContext.Provider>
  )
}

export default CustomThemeProvider

Here's how this looks in index.js...

import React from 'react'
import ReactDOM from 'react-dom'
import CssBaseline from '@material-ui/core/CssBaseline'
import App from './App'
import CustomThemeProvider from './themes/CustomThemeProvider'

ReactDOM.render(
  <CustomThemeProvider>
    {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
    <CssBaseline />
    <App />
  </CustomThemeProvider>,
  document.querySelector('#root'),
)

And then using the context in our App.js component...

export default function App() {
  const classes = useStyles()
  const { currentTheme, setTheme } = useContext(CustomThemeContext)
  const isDark = Boolean(currentTheme === 'dark')

  const handleThemeChange = (event) => {
    const { checked } = event.target
    if (checked) {
      setTheme('dark')
    } else {
      setTheme('normal')
    }
  }
...

The entire source for this as a working 'Create React App'-based repository, including the AppBar and Toggle controls can be found here...

https://github.com/infonomic/material-ui-theme-switcher

Here are a few additional links to theme and color related resources and tools that help in creating custom Material-based themes for Material-UI

  1. https://material-ui.com/customization/default-theme/
  2. https://material-ui.com/customization/color/
  3. https://material.io/design/color/the-color-system.html#color-usage-and-…
  4. https://material.io/resources/color/#!/?view.left=0&view.right=0
  5. https://react-theming.github.io/create-mui-theme/

Enjoy!

Category

Add new comment

The content of this field is kept private and will not be shown publicly.

Filtered HTML

  • Web page addresses and email addresses turn into links automatically.
  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.