How to Implement "dark mode" with Gatsby & React Hooks
Tags: react, javascript, css, showdev
Published: 2019-08-01 22:40:47

---
title: How to Implement "dark mode" with Gatsby & React Hooks
published: true
description: Persistent color theming for static sites 
tags: react, javascript, css, showdev
cover_image: https://thepracticaldev.s3.amazonaws.com/i/cgf5oscglodkh54utnnk.jpg
---

I recently launched my [new portfolio site](https://www.kimhart.nyc) and I have to say, I'm super proud! My old site was built on Wix years before I learned how to code and was in need of a major design update. 

I landed on [Gatsby](https://www.gatsbyjs.org/) for my setup and [Netlify](https://www.netlify.com/) for my deployment platform and guys, I cannot recommend each of them enough. But this post isn't about that!

## Why dark mode?

Turns out, a lot of people like dark-themed internet things (just ask Twitter). I chose to implement **toggleable sunrise and sunset themes** on my portfolio because it adds a level of interactivity to my otherwise static site, allowed me to play with more complex CSS, and it lets users customize their experience. It even persists through sessions via `localStorage`!

## What'd I use?
I considered building this myself until I found this tool called [use-dark-mode](https://github.com/donavon/use-dark-mode). In short, it's a custom React Hook that handles the storage part for you. Their docs are pretty great, but I'll walk you through my use case as well.

## Implementation
* You must use `react@16.8.0` or greater which includes Hooks
* This only works in **functional components**, so if you're using older React class components with non-hook lifecycle methods, you may have a hard time.

### 1. Install

You'll install both `use-dark-mode` and its Gatsby-specific plugin that helps with overall rendering of your themes:

```
yarn add use-dark-mode gatsby-plugin-use-dark-mode
```

### 2. Add to Gatsby config

To prevent a flash of default-styled content on page load, add this block to your `gatsby-config.js` file. (More in the [docs](https://www.gatsbyjs.org/packages/gatsby-plugin-use-dark-mode/))


```json
{
  resolve: "gatsby-plugin-use-dark-mode",
  options: {
     classNameDark: "dark-mode",
     classNameLight: "light-mode",
     storageKey: "darkMode",
     minify: true,
  },
}
```
Note: you can name these classes whatever you like! I stuck with the defaults.

### 3. Add to React

Here's a ultra-simplified version of my hero component. It contains two icon components (sunrise and sunset) that fire `handleTheme` on click, which launch either `darkMode.enable()` or `darkMode.disable()` depending on their props.

The goal here is to change to dark mode when you click sunset, and light mode when you click sunrise.

```jsx

import React from "react"
import useDarkMode from "use-dark-mode"
import Sunrise from "../components/icons/sunrise"
import Sunset from "../components/icons/sunset"

const Hero = () => {
  // Instantiate with the default behavior, in this case, it defaults to light-mode
 // This places "light-mode" class on document.body, as outlined in my gatsby-config.js
  const darkMode = useDarkMode(false);

  // Custom function that handles the toggling
  // When called, it replaces the class on document.body and holds it in localStorage
  const handleTheme = theme => theme === "dark" ? darkMode.enable() : darkMode.disable();
    
  return (
    <div className="hero">
      <Sunrise onClick={handleTheme} />
      <Sunset onClick={handleTheme} />
    </div>
  )
}

export default Hero;

```

The sunset and sunrise icon components are super similar, they just pass different values ("light" and "dark"). Here's a slimmed-down version of Sunset:


```jsx
import React from "react"

const Sunset = (props) => {
  // If the `onClick` prop exists, call it with 'dark'
  const handleClick = () => props.onClick && props.onClick('dark');
  
  return (
    <div className="theme-toggle" onClick={handleClick}>...</div>
  )
}
```
* Note: you could also accomplish this with passing boolean values (i.e. "true" for dark, but I chose to keep it more readable and used strings)


## CSS

Now that we have the class on `document.body` toggling between light-mode and dark-mode when we click the sunrise or sunset icons, we can adjust our CSS to reflect the changes.


I used Less, which makes it super easy to apply rules based on parent values. Again, this is simplified, but hopefully you get the idea.

The `.dark-mode &` selector will look for anytime the `dark-mode` class exists on a higher component (in this case, the `body` tag). You can then apply whatever rules you need — in this case it's a variable for the background colors.

```scss
   .hero {
      background: @sunrise-gradient;
      .dark-mode & {
        background: @sunset-gradient;
      }
    }
```

... and that's it!


## Conclusion

You don't have to completely recreate the wheel to implement dark mode in a Gatsby app. Hopefully this was helpful and I'm happy to answer any questions in the comments!