Create a Persisting Dark Mode with React

Create a Persisting Dark Mode with React


About the author

Telmo Goncalves is a software engineer with over 13 years of software development experience and an expert in React. He’s currently Engineering Team Lead at Marley Spoon.

Check out more of his work on telmo.is


images/create-a-persisting-dark-mode-with-react.jpg

A couple of weeks ago I published an article on how to implement a dark mode using only CSS and JavaScript.

This article uses the same approach but with React. One of the key advantages of using React is that the user’s choice between dark mode and light mode can persist when the page reloads.

This article assumes the reader has some introductory knowledge of React and general frontend development.

Setting up the app

First, set up a simple React component named App:

import React from "react";

import "./styles.css";

function App() {
  return (
    <div className="App">
      <h1>Hello, world!</h1>
      <h2>Let's create a dark mode toggle that persists when the page is reloaded.</h2>
    </div>
  );
}

export default App;

Notice that a styles.css file is being imported, so we’ll need to create one and apply the following declarations:

:root {
  --bg-color: #fff;
  --text-color: #000;
}

[data-theme="dark"] {
  --bg-color: #3F3F3F;
  --text-color: #fff;
}

.App {
  font-family: sans-serif;
  text-align: center;
  background-color: var(--bg-color);
  color: var(--text-color);
}

Now use useState to set the default value for darkMode, which will be false:

import React, { useState } from "react";

import "./styles.css";

function App() {
  const [darkMode, setDarkMode] = useState(false);

  // ...

Then update the div to include a data-theme attribute; the app will check if the value of darkMode is true and set the value to dark, otherwise, it will be light:

<div className="App" data-theme={darkMode ? "dark" : "light"}>
  <h1>Hello, world!</h1>
  <h2>Let's create a dark mode toggle that persists when the page is reloaded.</h2>
</div>

Now if useState() is changed from false to true, you’ll notice that the background of the .App div is set to black and the text color to white.


The Switch

Next, build out a function for switching between dark and light mode. Start by adding a new function which sets the theme either to light or to dark mode.

After useState(), add:

const toggleDarkMode = () => setDarkMode(darkMode ? false : true);

The example above is a little more verbose than it needs to be so the logic is clear to follow. The ternary darkMode ? false : true can be refactored to just !darkMode.

Since darkMode is a boolean data type, this sets the opposite value. For example:

let darkMode = true;

darkMode = !darkMode; // false
darkMode = !darkMode; // true
darkMode = !darkMode; // false
darkMode = !darkMode; // true

Adding a toggle button

Now that the toggleDarkMode function in place, create a <button> within the .App div so the user can invoke it:

<button onClick={toggleDarkMode}>
  Toggle Dark Mode
</button>

After applying this, you should be able to switch between light and dark modes. It’d be better if the button were more descriptive, though.

The darkMode state can be used to determine state and update the button to be clearer:

<button onClick={toggleDarkMode}>
  {darkMode ? "Switch to Light Mode" : "Switch to Dark Mode"}
</button>

Persisting light/dark mode

Currently, if the user selects dark mode and refreshes the page, it will revert to light mode. Ideally, the user’s selection should persist so they don’t need to change back to dark mode every time they open the page.

To do this, use React’s useEffect and localStorage.

First, update the React import to include useEffect:

import React, { useState, useEffect } from "react";

useEffect will allow for select code to be run every time a value changes. In this case, the code will be run when darkMode changes.

After the toggleDarkMode function, add:

useEffect(() => {
  console.log(`Is in dark mode? ${darkMode}`);
}, [darkMode]);

Now you’ll have visibility via the browser console into what’s happening every time dark mode is toggled.

After confirming this is working as expected, store the value in localStorage. Replace the console.log line with the following:

localStorage.setItem("DARK_MODE", darkMode);

Now the app needs to read the value of DARK_MODE from localStorage and set the default darkMode value.

Above useState, add the following to read the value from localStorage:

const storedDarkMode = localStorage.getItem("DARK_MODE");

Now that we have the value, it can be used to set the darkMode default value:

const [darkMode, setDarkMode] = useState(storedDarkMode);

Since the selection persists in localStorage, the app maintains the user’s selected state even if the page is reloaded.


Telmo regularly posts helpful React development tips and guides on Twitter. Be sure to follow him at @telmo


About PullRequest

HackerOne PullRequest is a platform for code review, built for teams of all sizes. We have a network of expert engineers enhanced by AI, to help you ship secure code, faster.

Learn more about PullRequest

Telmo Goncalves headshot
by Telmo Goncalves

November 4, 2020