DEV Community

loading...

How To add dark mode easily with a custom React hook

smakosh
Self-taught graphic, UI/UX designer and full stack JavaScript developer, loves open source and building side projects while working with startups.
Originally published at smakosh.com on ・2 min read

This article was originally published on my blog

In this quick article, I will be implementing dark mode to a small React app with a custom React hook,

Before we start, let’s see how is this supposed to work in three easy steps:

  1. We will check first if the chosen theme isn’t stored on localStorage
  2. If it exists, we will simply set it as the default theme
  3. Otherwise, we will have to use the light theme as the default one

So let’s get started!

Let’s start by setting up the custom hook first, we will be using useEffect & useState imported from React, we will check localStorage when the component mounts for the first time, then we’ll follow the second step!

import { useEffect, useState } from 'react'

export default () => {
  const [theme, setTheme] = useState('light')

  useEffect(() => {
    const localTheme = window.localStorage.getItem('theme')
    if (localTheme) {
      setTheme(localTheme)
    }
  }, [])
}

Let’s setup a function now that toggles in between themes and stores the selected theme in localStorage

import { useEffect, useState } from 'react'

export default () => {
  const [theme, setTheme] = useState('light')

  const toggleTheme = () => {
    if (theme === 'light') {
      window.localStorage.setItem('theme', 'dark')
      setTheme('dark')
    } else {
      window.localStorage.setItem('theme', 'light')
      setTheme('light')
    }
  }

  useEffect(() => {
    const localTheme = window.localStorage.getItem('theme')
    if (localTheme) {
      setTheme(localTheme)
    }
  }, [])
}

All good now, we only need to return the theme value along with the function so we can access it when we import the custom hook!

import { useEffect, useState } from 'react'

export default () => {
  const [theme, setTheme] = useState('light')

  const toggleTheme = () => {
    if (theme === 'light') {
      window.localStorage.setItem('theme', 'dark')
      setTheme('dark')
    } else {
      window.localStorage.setItem('theme', 'light')
      setTheme('light')
    }
  }

  useEffect(() => {
    const localTheme = window.localStorage.getItem('theme')
    if (localTheme) {
      setTheme(localTheme)
    }
  }, [])

  return [
    theme,
    toggleTheme,
  ]
}

Finally, let’s see how we can use it when we import it

import React from 'react'
import useDarkMode from './useDarkMode'

export default () => {
  const [ theme, toggleTheme ] = useDarkMode()
  return (
    <div
      style={{
        background: theme === 'dark' ? '#000' : '#fff',
        color: theme === 'dark' ? '#fff' : '#000',
      }}
    >
      <button type="button" onClick={toggleTheme}>
        Switch theme
      </button>
    </div>
  )
}

If you wish to implement it to a large app like I did on my website, you might have to use React Context API to have access to the theme & toggleTheme values anywhere in your app.

Discussion (3)

Collapse
dance2die profile image
Sung M. Kim

That's a clever use of localStorage 👍

And I'd like to mention that you can embed your Sandbox example using the markdown on the post like,

{% codesandbox mjm4zy7pm8 %}

, which will render as shown below.

For more info on embedding, check out the Editor Guide page 🙂

Collapse
smakosh profile image
smakosh Author

Thank u! & Thanks for the tip!

Collapse
algokun profile image
MOhan

Worth Reading it !! 👏 👏