How to implement theme toggler in tailwind CSS v4 in React project
Theme handler
First, we need a button or a component that will toggle dark and light mode.
Into the component, we need useState
to hold the context's current value.
Create the Theme Controller component
Button.jsx
const DarkModeToggler = () => {
return (
<>
<button>
{darkMode ? "Dark" : "Light" }
</button>
)
};
Use in CSS file. The file could be index.css
or global.css
or something else.
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
Create Context
Now create a context. It should look like this src/context/ThemeContext.jsx
. Into the ThemeContext.jsx
component we will implement the react context's logic.
import {createContext, useEffect, useState } from "react";
const ThemeContext = createContext('light');
const ThemeProvider = ({children}) => {
const [darkMode, setDarkMode] = useState(
localStorage.getItem("theme") === "dark"
)
return(
<ThemeContext.Provider value={{darkMode,setDarkMode}}>
{children}
</ThemeContext.Provider>
)
}
Here we can use hard-coded useState
logic. Like const [darkMode, setDarkMode] = useState('light')
. This will also work. But when a user refreshes the page the useState
value will be re-seted. To prevent this issue we used localStorage, which is the current value for darkMode
.To know when to use dark mode and when to use light mode, we need to use useEffect
.
useEffect(() => {
if(darkMode) {
document.documentElement.classList.add("dark");
localStorage.setItem("theme", "dark");
} else {
document.documentElement.classList.remove("dark");
loacalStorage.setItem("theme", "light");
}
},
[darkMode])
Here,
import { createContext, useContext, useEffect, useState } from "react";
const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const [darkMode, setDarkMode] = useState(
localStorage.getItem("theme") === "dark"
);
useEffect(() => {
if (darkMode) {
document.documentElement.classList.add("dark");
localStorage.setItem("theme", "dark");
} else {
document.documentElement.classList.remove("dark");
localStorage.setItem("theme", "light");
}
}, [darkMode]);
return (
<ThemeContext.Provider value={{ darkMode, setDarkMode }}>
{children}
</ThemeContext.Provider>
);
};
export const useDarkMode = () => useContext(ThemeContext);
Export ThemeContext
export const useDarkMode = () => useContext(ThemeContext)
NB: Don't forget to export the component export const ThemeProvider = () => {...}
Here is the final code for ThemeContext.jsx
import { createContext, useContext, useState, useEffect } from "react";
const ThemeContext = createContext("light");
export const ThemeProvider = ({ children }) => {
const [darkMode, setDarkMode] = useState(
localStorage.getItem("theme") === "dark"
);
useEffect(() => {
if (darkMode) {
document.documentElement.classList.add("dark");
localStorage.setItem("theme", "dark");
} else {
document.documentElement.classList.remove("dark");
localStorage.setItem("theme", "light");
}
}, [darkMode]);
return (
<ThemeContext.Provider value={{ darkMode, setDarkMode }}>
{children}
</ThemeContext.Provider>
);
};
export const useDarkMode = () => useContext(ThemeContext);
Now we are ready to use controlling them.
To implement we have to go to the root component.main.jsx
and wrap it with <ThemeProvider> ...</ThemeProvider>
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import ThemeProvider from "./context/ThemeContext.jsx";
import "./index.css";
ReactDOM.createRoot(document.getElementById("root")).render(
<ThemeProvider>
<App />
</ThemeProvider>
);
Change the state in the toggler component(DarkModeToggler.jsx
) and import state
from ThemeContext
. To toggle them we need an onClick
and a handlerfunction
The component should look like this.
import { useContext } from "react";
import { ThemeContext } from "../context/ThemeContext";
const DarkModeToggler = () => {
const { darkMode, setDarkMode } = useContext(ThemeContext);
return (
<button
onClick={() => setDarkMode((prev) => !prev)}
className="p-2 border rounded"
>
{darkMode ? "Light Mode" : "Dark Mode"}
</button>
);
};
export default DarkModeToggler;
Now we are ready to use dark and light mode in our application.
Here is a simple example of how to use the theme.
import { useDarkMode } from "../context/ThemeContext";
const Card = () => {
const { darkMode } = useDarkMode();
return (
<div className="p-5 rounded-lg shadow-lg border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
<h2 className="text-xl font-bold">Dark Mode Card</h2>
<p className="mt-2">This card changes theme based on the mode.</p>
<button className="mt-4 px-4 py-2 bg-blue-500 dark:bg-blue-700 text-white rounded-lg">
Click Me
</button>
</div>
);
};
export default Card;
Top comments (0)