[Gatsby, TailwindCSS] Integrate dark mode in 10 minutes
Tags: gatsby, tailwindcss, react
Published: 2021-05-14 22:04:44

Hi there!

I'm Arisa, a DevRel from this June living in Germany🇩🇪 (A big announcement is coming this June😏)

I have a free online programming learning community called [Lilac](https://note.com/frontendlifeinde/m/m9b8feda1d547), with [free hands-on Frontend e-books](https://zenn.dev/arisa_dev/books)👩‍💻

# Who is this article for?

- Anyone wants to integrate dark mode🌘
- Anyone wants to integrate multiple themes

# Step 1: Install TailwindCSS

```shell
$ yarn add tailwindcss
```

If you want to generate `tailwind.config.js` file, run this👇

```shell
$ npx tailwindcss init
``` 

# Step 2: Install `gatsby-plugin-postcss`

```shell
$ yarn add postcss gatsby-plugin-postcss
``` 

Make sure to add in `gatsby-config.js` file too.

```javascript
plugins: [`gatsby-plugin-postcss`]
```

> [Gatsby.js: gatsby-plugin-postcss](https://www.gatsbyjs.com/plugins/gatsby-plugin-postcss/)

# Step 3: Create a `postcss.config.js` file

Create a `postcss.config.js` file in a root directory.

Add the configuration like below.

```javascript
module.exports = () => ({
  plugins: [require("tailwindcss")],
})
```

> [TailwindCSS: Using PostCSS as your preprocessor](https://tailwindcss.com/docs/using-with-preprocessors#using-post-css-as-your-preprocessor)

# Step 4: Edit global styles, `src/components/layout.css`

Swap default styles to these 3 lines.

```javascript
@tailwind base;
@tailwind components;
@tailwind utilities;
```

These are Tailwind directives to enable Tailwind styles.

Also, we can already add a dark theme and light theme at this point in the same file.

```javascript
@tailwind base;
@tailwind components;
@tailwind utilities;

body.dark {
  --primary: #111827;
  --text-main: white;
}

body.light {
  --primary: white;
  --text-main: #111827;
}
```

We'll use those variables in `tailwind.config.js` file.

```javascript
module.exports = {
  purge: [],
  darkMode: 'class',
  theme: {
      extend: {
        colors: {
          primary: 'var(--primary)',
          'text-main': 'var(--text-main)',
        }
      },
  },
  variants: {
      extend: {},
  },
  plugins: [],
}
```

If your variable name contains a hyphen like ablve, make sure to set it as a string when you call it in a config file.

Camel case doesn't work in here.

# Step 5: Test dark mode first

At this point, we don't have anything like a button or checkbox to trigger the change of the theme styles.

But not so fast.

We need to make sure first whether TailwindCSS is integrated or not by applying some styles.

Go to TailwindCSS documentation.

Let's apply something dark gray from what we can choose from their documentation.

> [TailwindCSS: Background color](https://tailwindcss.com/docs/background-color)

```javascript
import * as React from "react"
import PropTypes from "prop-types"
import { useStaticQuery, graphql } from "gatsby"

import Header from "./header"
import "./layout.css"

const Layout = ({ children }) => {
  const data = useStaticQuery(graphql`
    query SiteTitleQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
  `)

  return (
    <div className="bg-gray-900 text-white">
      <Header siteTitle={data.site.siteMetadata?.title || `Title`} />
      <div
        style={{
          margin: `0 auto`,
          maxWidth: 960,
          padding: `0 1.0875rem 1.45rem`,
        }}
      >
        <main>{children}</main>
        <footer
          style={{
            marginTop: `2rem`,
          }}
        >
          © {new Date().getFullYear()}, Built with
          {` `}
          <a href="https://www.gatsbyjs.com">Gatsby</a>
        </footer>
      </div>
    </div>
  )
}

Layout.propTypes = {
  children: PropTypes.node.isRequired,
}

export default Layout
```

We can check in the browser by running the development mode.

```shell
$ yarn develop
```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cnsey21yj0da7kjzs4jf.png)

We can confirm that TailwindCSS is working fine in our project💃

Let's rock more 😎

# Step 6: Create a dark mode theme

Add a config in `tailwind.config.js`

```javascript
module.exports = {
  purge: [],
  darkMode: 'class',// 👈 he's your guest
  theme: {},
  variants: {
      extend: {},
  },
  plugins: [],
}
```

We're toggling a dark mode manually.

Here is what I followed from the documentation.

> [TailwindCSS: Toggling dark mode manually](https://tailwindcss.com/docs/dark-mode#toggling-dark-mode-manually)

# Step 7: Update class attribute in `layout.js`

We created a dark theme and a light theme.

Also, we configured that we'll manually toggle dark mode.

At this point, we can already apply the variables we prepared.

Open your `layout.js` file.

You can only swap the class attribute values when we tested the dark theme to see TailwindCSS is enabled.

```javascript
// same as previous code

 return (
    {/* 👇 use variables in here */}
    <div className="theme-dark bg-primary text-text-main">
      <Header siteTitle={data.site.siteMetadata?.title || `Title`} />
      <div
        style={{
          margin: `0 auto`,
          maxWidth: 960,
          padding: `0 1.0875rem 1.45rem`,
        }}
      >
        <main>{children}</main>
        <footer
          style={{
            marginTop: `2rem`,
          }}
        >
          © {new Date().getFullYear()}, Built with
          {` `}
          <a href="https://www.gatsbyjs.com">Gatsby</a>
        </footer>
      </div>
    </div>
  )
// same as previous code
```

Wondered where all these `theme`, `bg-` and `text-` came from?

Those are all from `tailwind.config.js`.

It's like a path to fetch data.

# Step 8: Install `gatsby-plugin-dark-mode` 

Gatsby made our life so much easier.

Simply, just install this plugin first.

```shell
$ yarn add gatsby-plugin-dark-mode
```

Of course, include it in `gatsby-config.js` file as any other plugins.

```javascript
plugins: [`gatsby-plugin-dark-mode`]
```

# Step 9: Create a `src/components/themeToggle.js` file

Create a `themeToggle.js` in under the directory of `src/components`.

Actually, all we need to do in here is just use the example from Gatsby's documentation.

> [Gatsby.js: gatsby-plugin-dark-mode](https://www.gatsbyjs.com/plugins/gatsby-plugin-dark-mode/)

```javascript
import React from 'react'
import { ThemeToggler } from 'gatsby-plugin-dark-mode'

export default function ThemeToggle() {
  return(
    <ThemeToggler>
      {({ theme, toggleTheme }) => {
        if (theme == null) return null
        return(
          <label>
            <input
              type="checkbox"
              onChange={e => toggleTheme(e.target.checked ? 'dark' : 'light')}
              checked={theme === 'dark'}
            />{' '}
            <span></span>
          </label>
        )}
      }
    </ThemeToggler>
  )
}
```

> 💡 A note: `gatsby-plugin-dark-mode` had an issue that can't switch from dark mode to light mode in the first load of the page until clicking 3 times. Above is from the latest commit from this plugin but not yet in a latest release.

> [Theme toggle requires 2-3 clicks before changing theme #13](https://github.com/insin/gatsby-plugin-dark-mode/issues/13)

Then we'll import themeToggle component into the page or component we want to enable.

This time, I want to have in my header navigation menu.

Let's import in a header component.

```javascript
import * as React from "react"
import PropTypes from "prop-types"
import { Link } from "gatsby"
import ThemeToggle from '../components/themeToggle'// 👈

const Header = ({ siteTitle }) => (
  <header
    style={{
      marginBottom: `1.45rem`,
    }}
  >
    <div
      style={{
        margin: `0 auto`,
        maxWidth: 960,
        padding: `1.45rem 1.0875rem`,
      }}
      className="flex justify-between"
    >
      <h1 style={{ margin: 0 }}>
        <Link
          className="text-2xl font-black"
          to="/"
        >
          {siteTitle}
        </Link>
      </h1>
      <ul className="grid grid-cols-2 gap-4">
　　　　　{/* 👇 */}
        <li>
          <ThemeToggle />
        </li>
        <li>
          <Link to="/" className="text-base font-semibold text-gray-400">
            Blog
          </Link>
        </li>
        <li>
          <Link to="/" className="text-base font-semibold text-gray-400">
            Talk
          </Link>
        </li>
      </ul>
    </div>
  </header>
)

Header.propTypes = {
  siteTitle: PropTypes.string,
}

Header.defaultProps = {
  siteTitle: ``,
}

export default Header
```

It works like a magic🧙‍♂️

- dark mode disabled

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ziv4x92bhl3eg5s2f9y7.png)

- dark mode checked

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4of5z1wfmbb9nl02uodf.png)

Hope you found something useful from this blog post!

These sources were helpful too🙌
> [Create a dark mode theme switch with Gatsby and TailwindCSS](https://javascript.plainenglish.io/create-a-dark-mode-theme-switch-with-gatsby-and-tailwindcss-d7691f337998)

> [Create a CSS Theme Switcher Using Gatsby and TailwindCSS](https://levelup.gitconnected.com/create-a-css-theme-switcher-using-gatsby-and-tailwindcss-aca85f93bd1f)