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
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