DEV Community

Cover image for [Gatsby, TailwindCSS] Integrate dark mode in 10 minutes
Arisa Fukuzaki
Arisa Fukuzaki

Posted on • Edited on

[Gatsby, TailwindCSS] Integrate dark mode in 10 minutes

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, with free hands-on Frontend e-books👩‍💻

Who is this article for?

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

Step 1: Install TailwindCSS

$ yarn add tailwindcss
Enter fullscreen mode Exit fullscreen mode

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

$ npx tailwindcss init
Enter fullscreen mode Exit fullscreen mode

Step 2: Install gatsby-plugin-postcss

$ yarn add postcss gatsby-plugin-postcss
Enter fullscreen mode Exit fullscreen mode

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

plugins: [`gatsby-plugin-postcss`]
Enter fullscreen mode Exit fullscreen mode

Gatsby.js: 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.

module.exports = () => ({
  plugins: [require("tailwindcss")],
})
Enter fullscreen mode Exit fullscreen mode

TailwindCSS: Using PostCSS as your preprocessor

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

Swap default styles to these 3 lines.

@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

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.

@tailwind base;
@tailwind components;
@tailwind utilities;

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

body.light {
  --primary: white;
  --text-main: #111827;
}
Enter fullscreen mode Exit fullscreen mode

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

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

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

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
Enter fullscreen mode Exit fullscreen mode

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

$ yarn develop
Enter fullscreen mode Exit fullscreen mode

Alt Text

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

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

We're toggling a dark mode manually.

Here is what I followed from the documentation.

TailwindCSS: 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.

// 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
Enter fullscreen mode Exit fullscreen mode

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.

$ yarn add gatsby-plugin-dark-mode
Enter fullscreen mode Exit fullscreen mode

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

plugins: [`gatsby-plugin-dark-mode`]
Enter fullscreen mode Exit fullscreen 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

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>
  )
}
Enter fullscreen mode Exit fullscreen mode

💡 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

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.

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
Enter fullscreen mode Exit fullscreen mode

It works like a magic🧙‍♂️

  • dark mode disabled

Alt Text

  • dark mode checked

Alt Text

Hope you found something useful from this blog post!

These sources were helpful too🙌

Create a dark mode theme switch with Gatsby and TailwindCSS

Create a CSS Theme Switcher Using Gatsby and TailwindCSS

Top comments (1)

Collapse
 
achilleskal profile image
Achilles Kaloeridis

In paragraph 4, I think there is a typo, "a hyphen like ablve".
Also 'gatsby-plugin-dark-mode' does not seem to work, it is probably outdated. There is a fork that works: npmjs.com/package/@skagami/gatsby-...

Thanks for the article!