
Light to dark mode theme: 3 easy steps to do it in your ReactJS app using TailwindCSS
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:
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
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
andtoggler
- 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:
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 havejsx
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 isuseToggle.js
while other files like app and navbar are saved asApp.jsx
andNavbar.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:
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.
👇
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:
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:
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 ✌️