Set up Light and Dark Theme in React

light/dark

Why am I writing this?

When I started web development in React I stumbled across the idea of making a dark and light mode in a webapp, that is to change the theme of the whole website by a single click, so I started searching through the web to add this feature to my app. I found many articles that could make it happen but as a beginner they were too difficult for me and at some point I felt lost. Eventually I found an answer on stackoverflow that showed my the most simple way of updating the state of a component from inside another component though it was not related to theming but it helped me in making a light and dark mode for a react app in a most simple way.

Let’s get started

With the release of React 16.8 hooks are added to the react and are recommended to be used as they add simplicity to the code so I will use functional components along with useState and useContext hooks. I have created my project using create-react-app. I will provide the link to the github repository in the end of this post.


Steps to implement theming:

In my app.js file I have imported four components that I have created. I will explain each of these components later. This is how my app.js file should looks like:

import React from 'react'
import { ThemeContextProvider } from './components/ThemeProvider'
import AppBar from './components/AppBar'
import Footer from './components/Footer'
import ToggleTheme from './components/ToggleTheme'

function App() {

 return (
    <ThemeContextProvider>
      <AppBar />
      <ToggleTheme />
      <Footer />
    </ThemeContextProvider>
  )
}

export default App

Below is my code from ThemeProvider.js file in which I have created a context named ThemeContext and a functional component named ThemeContextProvider. To be able to change the theme of all the components inside out app we must wrap all the components with ThemeContextProvider so that we can consume the value of context inside other components. In the setState method I have used spread operator […state] to preserve the values of other state variables. Now whenever setTheme method is called from any component the value of context gets updated.

import React, { useState } from 'react'

export const ThemeContext = React.createContext({
  theme: {
    type: 'light',
    primary: '#00bfa5',
    text: '#black'
  },
  setTheme: () => {}
})

export const ThemeContextProvider = props => {
  const theme = {
    light: {
      type: 'light',
      primary: '#0277bd',
      text: 'black'
    },
    dark:{
      type: 'dark',
      primary: '#212121',
      text: 'white'
    },
  }

  const setTheme = type => {
    setState({ ...state, theme: type === 'dark' ? theme.light : theme.dark })
  }

  const initState = {
    theme: theme.light,
    setTheme: setTheme
  }

  const [state, setState] = useState(initState)

  return (
    <ThemeContext.Provider value={state}>
      {props.children}
    </ThemeContext.Provider>
  )
}

In AppBar component I have created a simple appbar with a background color and some header text. As I am using the value of context to set the background and text color and the way that context works is that whenever the value of context gets updated every component that uses it gets re rendered which in our case switches from light theme to dark and vice versa.

import React, { useContext } from 'react'
import { ThemeContext } from './ThemeProvider'

const AppBar = () => {
  const state = useContext(ThemeContext)

  const appBar = {
    marginTop: 0,
    backgroundColor: state.theme.primary,
    width: '100%',
    height: '60px',
    color: state.theme.text
  }

  return (
    <div style={appBar}>
      <h1>Dark and light Theme</h1>
    </div>
  )
}

export default AppBar

ToggleTheme.js is the file which triggers the setTheme method to switch Theme Mode. It contains a button with an onClick() property in which we call the setTheme method. Since we have stored the setTheme method in the value of context so we can update its value at any place by accessing it through useContext() hook.

import React, { useContext } from 'react'
import { ThemeContext } from './ThemeProvider'

function ToggleTheme() {
  const state = useContext(ThemeContext)

  const btn = {
    color: state.theme.textOnSecondary,
    marginTop: '20px',
    marginBottom: '20px',
    background: state.theme.secondary
  }

  return (
    <button
      variant='contained'
      onClick={() => {
        state.setTheme(state.theme.type)
      }}
      style={btn}
    >
      Toggle Theme
    </button>
  )
}

export default ToggleTheme

Just like appbar footer is also a component with some text on it. Its colours also change as we toggle theme Mode.

import React, { useContext } from 'react'
import { ThemeContext } from './ThemeProvider'

export default function Footer() {
  const state = useContext(ThemeContext)

  const footer = {
    backgroundColor: state.theme.primary,
    color: state.theme.text,
    width: '100%',
    height: '50px',
  }

  return (
   <div style={footer}>
     This is a Footer
   </div>
  )
}

Here is the link to my github repository for this post. To install all the dependecies Run npm install before starting the server.


Yeah thats it nice and simple, if you have any question regarding this post let me know in the comments section!


Leave a Reply

Your email address will not be published. Required fields are marked *