Light to dark mode theme: 3 easy steps to do it in your ReactJS app using TailwindCSS

Light to dark mode theme: 3 easy steps to do it in your ReactJS app using TailwindCSS

The React Newbie's photo
The React Newbie
ยทJul 1, 2022ยท

5 min read

Subscribe to my newsletter and never miss my upcoming articles

Play this article

Table of contents

  • Step 1: What we already have
  • Step 2: Let's bring in TailwindCSS
  • Step 3: Making our theme switchable
  • Make your own changes!

Hi there ๐Ÿ‘‹

To make this article as concise as possible, we will reuse the ReactJS app we created here since it has content in it already.

Screenshot of what our app looks at the moment:

tutorial 2.png

Now let's change the theme of the app from light to dark and vice versa.

Step 1: What we already have

We have a useToggle custom hooks that give us the ability to show an element conditionally.

We used it previously to show/hide a modal.

Now let's use it to change the icon on our navbar

tutorial 2 (2)_LI.jpg

Open Navbar.jsx and add this code to it:

import React from "react";
import useToggle from "../Hooks/useToggle"; // line 2

export default function Navbar() {
  const { on, toggler } = useToggle(); // line 5

  return (
    <nav className="flex items-center justify-between flex-wrap bg-teal-500 p-4">
      <div className="flex items-center flex-shrink-0 text-white mr-6">
        <svg
          className="fill-current h-8 w-8 mr-2"
          width="54"
          height="54"
          viewBox="0 0 54 54"
          xmlns="http://www.w3.org/2000/svg"
        >
          <path d="M13.5 22.1c1.8-7.2 6.3-10.8 13.5-10.8 10.8 0 12.15 8.1 17.55 9.45 3.6.9 6.75-.45 9.45-4.05-1.8 7.2-6.3 10.8-13.5 10.8-10.8 0-12.15-8.1-17.55-9.45-3.6-.9-6.75.45-9.45 4.05zM0 38.3c1.8-7.2 6.3-10.8 13.5-10.8 10.8 0 12.15 8.1 17.55 9.45 3.6.9 6.75-.45 9.45-4.05-1.8 7.2-6.3 10.8-13.5 10.8-10.8 0-12.15-8.1-17.55-9.45-3.6-.9-6.75.45-9.45 4.05z" />
        </svg>
        <span className="font-semibold text-xl tracking-tight">
          Tailwind Shop
        </span>
      </div>

      {/* toggle button - line 24 and below */}
      <div className="block">
        <button
          onClick={toggler} // line 32
          className="flex items-center px-3 py-2 text-teal-200 border-teal-400 hover:text-white hover:border-white"
        >
          {on ? ( // render what is here if on is true
            <svg
              xmlns="http://www.w3.org/2000/svg"
              className="h-6 w-6"
              fill="none"
              viewBox="0 0 24 24"
              stroke="currentColor"
              strokeWidth="2"
            >
              <path
                strokeLinecap="round"
                strokeLinejoin="round"
                d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"
              />
            </svg>
          ) : ( // render what is here if on is false
            <svg
              xmlns="http://www.w3.org/2000/svg"
              className="h-6 w-6"
              fill="none"
              viewBox="0 0 24 24"
              stroke="currentColor"
              strokeWidth="2"
            >
              <path
                strokeLinecap="round"
                strokeLinejoin="round"
                d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"
              />
            </svg>
          )}
        </button>
      </div>
    </nav>
  );
}

Explanation

  • On line 2, we imported the useToggle hook
  • On line 5, we destructured the properties that are inside the useToggle hook. on and toggler
  • Then from line 24 downwards we conditionally render two icons based on the value of on
  • Notice on line 32, we have an event that calls toggler whenever the button is clicked and toggler changes the value of on to either true or false. See below for more details:
{on 
    ? ( // render what is here if on is true ) 
  or
    : (  // render what is here if on is false)
}

Go back to your app to view changes:

toggle button.gif

Well done! The icon changes don't it? But our app is still on light mode.

Please note: Our file extension is in .jsx because we created the app with Vite. Vite requires that we use .jsx when we have jsx code in a file but we can use .js when it's just JavaScript code present in a file. Take for example our useToggle Hook is useToggle.js while other files like app and navbar are saved as App.jsx and Navbar.jsx.

Step 2: Let's bring in TailwindCSS

First, we enable dark mode in our tailwind.config.js file like this:

module.exports = {
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  darkMode: "class", // add this
  theme: {
    extend: {},
  },
  plugins: [],
};

Next, we add a dark class attribute to our <html> tag like this:

<html lang="en" class="dark">

and then we can specify how each component of our app should be.

To make the entire app have a darkish background on dark mode, edit App.jsx like this:

import React, { useEffect } from "react";
import Navbar from "./Components/Navbar";
import Product from "./Components/Product";
import Modal from "./Components/Modal";
import useToggle from "./Hooks/useToggle";

export default function App() {
  const { on, toggler } = useToggle();

  return (
    <div 
      className="bg-white dark:bg-slate-800 h-screen" // just added
    >
      <Navbar />
      <div className="flex justify-center">
        <Product toggler={toggler} />
      </div>
      {on && <Modal toggler={toggler} />}
    </div>
  );
}

This means that our app will have this bg-white background in light mode and a bg-slate-800 background in dark mode.

Save your file and go see the changes:

dark mode.gif

Our app is currently in dark mode but when we click the button, it doesn't switch to light mode.

Just one more step to go.

Step 3: Making our theme switchable

We need a function to do this.

Let's create the function in our Navbar.jsx since that's where the toggle button is.

In our Navbar.jsx file, add this function just after line 5:

const themeToggler = () => {
    toggler() // this changes the icon on the navbar
    document.documentElement.classList.toggle("dark"); // this add or removes 'dark' as a class in the html document of our app
  };

Explanation

  • toggler() changes the icon of the button on the navbar
  • We use document.documentElement.classList to access the <html> tag class attribute of the DOM while document.documentElement.classList.toggle("dark") is a method that adds or removes the class "dark" from it.

Now by calling one function, themeToggler, we can change both the icon of the button on the navbar and the theme of our app.

Cool right?

Change the onclick event on line 32 in Navbar.jsx to call themeToggler:

onClick={themeToggler} // line 32

Now whenever we click on the button in the navbar, the icon will change and so will the theme of the app.

๐Ÿ‘‡ dark mode toggle.gif

It's working!!! ๐Ÿ™Œ๐Ÿ™Œ๐Ÿ™Œ

Nice!

Remember we hard-coded dark class to the <html> tag in index.html.

We should remove it so that our app will initially be on light mode until the user uses the toggle button.

Do this:

<html lang="en">
// we removed class="dark"

Now your app should look like this:

dark mode toggle final.gif

And we are done! Finally! ๐Ÿ™‡โ€โ™€๏ธ

Make your own changes!

Notice that the background of our navbar didn't change both on light and dark modes.

Try to edit the code so it changes and looks like this:

assignment.gif

Get your hands dirty with some coding practice and tweaking.

Feel free to reach out to me if you face any challenges doing so.

See ya โœŒ๏ธ

ย 
Share this