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 useStatelogic. 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)