Dark Mode Using React
Tags: javascript, react, tutorial, css
Published: 2022-01-04 03:41:06

## Dark mode is a common feature to see on modern websites, here's how to make your own with React.

> Originally posted [Here](https://www.tobyhagan.com/blog/dark-mode-using-react)

### Looks Cool, But Why?

If you've ever worked in front of a screen, you probably know how it feels to finally get away from the computer, only to have your eyes strained over the course of the day. One way developers have started to combat this is the use of dark mode. Dark mode uses light text on a dark background, also leading to lower power consumption on certain devices. This is also a great tool in keeping users engaged and interested in your content.

### Creating a React App

First, we need to create a react app. The most popular way to do this is to run the following command:

```bash
npx create-react-app dark-mode-example
```

This will create a directory called `dark-mode-example`, and will install React and the necessary dependencies to get you started. Once that is complete, you should see the following in the terminal:

```bash
Success! Created dark-mode-example at /home/example/dark-mode-example
Inside that directory, you can run several commands:

  npm start
    Starts the development server.

  npm run build
    Bundles the app into static files for production.

  npm test
    Starts the test runner.

  npm run eject
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you can’t go back!

We suggest that you begin by typing:

  cd dark-mode-example
  npm start

Happy hacking!
```

### Verifying Installation

Now that our React app is set up, lets run `cd dark-mode-example` and `npm start` to start the development server. A Browser window will open in your default browser, and you should see the following:

<img src="https://storage.googleapis.com/tobyhagan_post_images/create-react-app.webp" width="1600" height="774" alt="Default create-react-app template" />

Now we can open our favorite text editor and start coding. I recommend using VS Code, so we can stop our development server with `ctrl + c` and then run `code .` since we're already in the project directory. For the purposes of this tutorial, we'll only be editing two files: `src/App.js` and `src/App.css`. We can start by editing `src/App.js`:

It should currently look something like this:

```js
import logo from "./logo.svg";
import "./App.css";

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;
```

Remove the header tag and everything within, only leaving the following:

```js
import "./App.css";

function App() {
  return <div className="App"></div>;
}

export default App;
```

Now we can edit `src/App.css`. It should currently contain the following:

```css
.App {
  text-align: center;
}

.App-logo {
  height: 40vmin;
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  .App-logo {
    animation: App-logo-spin infinite 20s linear;
  }
}

.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}

.App-link {
  color: #61dafb;
}

@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}
```

We removed almost everything that relies on this file in the previous step, so remove everything except the `.App` class. The file should now look like this:

```css
.App {
  text-align: center;
}
```

While we have this file open, lets update the `.App` class, and add a few more classes we'll use in the following steps:

```css
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
.App {
  height: 100vh;
  width: auto;
  text-align: center;
  font-size: 5em;
  color: #2e3440;
  background-color: #d8dee9;
  transition: all 0.2s ease;
}
.dark,
.dark .App {
  color: #d8dee9;
  background-color: #2e3440;
  transition: all 0.2s ease;
}
```

Lets talk about what we've done here. The first change you may notice is the `*` selector. This is a universal selector, and will apply to all elements. This serves as a simple way to reset the default styles of all elements, creating a consistent look and feel across multiple browsers. We also added a new class called `.dark`. This class will be added to the `.App` class when the user clicks the dark mode button. The new styles will be applied, and any elements that are not in the `.dark` class will not be affected.

### Making a Dark Mode Button

Lets go back to `src/App.js` and add some text, and a button to toggle dark mode on and off. We'll assign the class `.dark-mode-toggle` to the button, and use the `onClick` event to toggle Dark Mode on and off. Because we're using `useState` to toggle Dark Mode, we'll import it at the top of the filee. Then we need to create our `darkMode` variable and setDarkMode modifier. For the time being we will default to `false`, which means the app will use light mode.

```js
import "./App.css";
import { useState } from "react";

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

  return (
    <div className="App">
      <h1>{darkMode ? "Dark Mode" : "Light Mode"}</h1>
      <p>This is a test</p>
      <button
        className="dark-mode-toggle"
        onClick={() => {
          setDarkMode(!darkMode);
        }}
      >
        {darkMode ? "Dark Mode" : "Light Mode"}
      </button>
    </div>
  );
}

export default App;
```

Once you've added the button, you can test it by clicking it. You should see the following:

<img src="https://storage.googleapis.com/tobyhagan_post_images/light-mode-tutorial.webp" width="1600" height="774" alt="Light Mode Tutorial">

Click the button and the header and button text should be updated to say `Dark Mode`, thanks to the ternary statements we just implemented. Here's what you should see after clicking the button:
<img src="https://storage.googleapis.com/tobyhagan_post_images/dark-mode-tutorial.webp" width="1600" height="774" alt="Dark Mode Tutorial">

### Make it do something

Awesome! We're toggling dark mode on and off with a button, but we're not changing any styling yet. To do this, we'll need to import `useEffect` alongside our existing `useState` hook. After importing `useEffect`, we can use it below our variable declarations. When using `useEffect`, we can pass in a function as the second argument. This function will be called after the component mounts, and will be called again whenever the `darkMode` variable changes. If the second argument is an empty function, then the effect will only run once when the component mounts. We can use this to add a listener to the `darkMode` variable, and then add or remove the `.dark` class from the body when it changes. Our `useEffect` hook will look like this:

```js
useEffect(() => {
  if (darkMode) {
    document.body.classList.add("dark");
  } else {
    document.body.classList.remove("dark");
  }
}, [darkMode]);
```

With this in place, our button starts to actually make some changes! When dark mode is active, we will see the following:
<img src="https://storage.googleapis.com/tobyhagan_post_images/dark-mode-tutorial-active.webp" width="1600" height="774" alt="Dark Mode Tutorial">

### Make it look nice

We need to update our button with a blank div to style into the slider button. First, remove the ternary statement from the label of the button, and replace it with a `div` element. Then, add a the class `.dark-mode-slider` to the div as shown below:

```js
<button
  className="dark-mode-toggle"
  onClick={() => {
    setDarkMode(!darkMode);
  }}
>
  <div className="dark-mode-slider" />
</button>
```

To achieve a nice slider look, we'll update `src/App.css` to add the `.dark-mode-toggle` and `.dark-mode-slider` classes from our button above. Add the following to `src/App.css`:

```css
/* Button Styles */

.dark-mode-toggle {
  width: 80px;
  height: 36px;
  border-radius: 50px;
  top: 0;
  left: 0;
}
.dark-mode-toggle svg {
  fill: #000;
}
.dark-mode-slider {
  height: 30px;
  width: 30px;
  border-radius: 50%;
  background-color: #2e3440;
  display: flex;
  position: relative;
  transform: translateX(0px);
  transition: all 0.2s ease;
}

.dark .dark-mode-slider {
  transform: translateX(45px);
}
```

Here you can see we have positioned the slider to the left for our default light mode, then when the `.dark` class is added to the body, we'll move the slider to the right using CSS transitions. This will give the slider a nice sliding effect, giving your application a nice polished feel. This is just the beginning of what we can do with dark mode, as you can store values to local storage, then access them when the user returns to the site. We'll be covering this in the next tutorial.