I built a custom Dark Mode for React + Tailwindcss
A short article to create your Dark Mode on React with Tailwindcss
I recently wrote an article on creating dark mode in Next.js. Today, I'm sharing an even quicker method in React.
Step 1: Install TailwindCSS and Lucide-React
Install TailwindCSS and lucide-react:
npm install tailwindcss lucide-react
# or
yarn add tailwindcss lucide-react
Step 2: Configure TailwindCSS for Dark Mode
Enable the dark mode class strategy in tailwind.config.js
:
module.exports = {
darkMode: ['class'],
// other configurations...
};
Step 3: Create a Dark Mode Toggle Component
Create a DarkMode
component to toggle dark mode:
"use client"
import { Moon, Sun } from "lucide-react";
import { useState, useEffect } from 'react';
export const useDarkMode = () => {
const [dark, setDark] = useState(false);
useEffect(() => {
const storedDarkMode = localStorage.getItem('dark-mode');
if (storedDarkMode) {
setDark(storedDarkMode === 'true');
}
}, []);
useEffect(() => {
localStorage.setItem('dark-mode', dark);
}, [dark]);
return [dark, setDark];
};
export default function DarkMode({ dark, setDark }) {
useEffect(() => {
if (typeof window !== "undefined") {
const root = window.document.documentElement;
if (dark) {
root.classList.add('dark');
} else {
root.classList.remove('dark');
}
}
}, [dark]);
return (
<div className="cursor-pointer" onClick={() => setDark(!dark)}>
{dark ? <Sun className="h-[1.2rem] w-[1.2rem]" /> : <Moon className="h-[1.2rem] w-[1.2rem]" />}
</div>
);
}
Here's a brief explanation of the code:
useDarkMode
Hook:Manages dark mode state using
useState
.Initializes state from
localStorage
and updates it on changes.Persists dark mode preference in
localStorage
.
DarkMode
Component:Uses
useEffect
to add or remove thedark
class on thehtml
element based on the dark mode state.Renders an icon that toggles dark mode on click (Moon for light mode, Sun for dark mode).
This setup allows for easy toggling and persistence of dark mode in a React app.
Step 4: Import your Dark Mode in your Header
You probably got a place where to import your Header.jsx
— layout, main or App.jsx:
import DarkMode, { useDarkMode } from '@/components/DarkMode';
export default function Header() {
const [dark, setDark] = useDarkMode();
return (
<header className="flex items-center justify-end p-4">
<DarkMode dark={dark} setDark={setDark} />
</header>
);
}
Step 5: Leverage your style in CSS/SCSS
Update your styles to support dark mode:
body {
@apply text-black min-h-screen dark:bg-slate-900 dark:text-white;
}
EDIT: Shortest version.
// header
import DarkMode from "@/components/DarkMode";
export default function Header() {
return (
<header className="flex items-center justify-end pt-4">
<DarkMode />
</header>
);
}
// DarkMode.jsx only (using react-use)
"use client"
import { Moon, Sun } from "lucide-react";
import { useEffect, useState } from 'react';
import { useLocalStorage } from 'react-use';
export default function DarkMode() {
const [dark, setDark] = useState(false);
const [value, setValue, remove] = useLocalStorage('dark-mode');
useEffect(() => {
if (value) setDark(value);
}, [value]);
useEffect(() => {
if (typeof window !== "undefined") {
const root = window.document.documentElement;
if (dark) {
root.classList.add('dark');
} else {
root.classList.remove('dark');
}
}
localStorage.setItem('dark-mode', dark);
}, [dark]);
return (
<div className="cursor-pointer" onClick={() => setDark(!dark)}>
{dark ? <Sun className="h-[1.2rem] w-[1.2rem]" /> : <Moon className="h-[1.2rem] w-[1.2rem]" />}
</div>
);
}
And that's it! You now have a functional dark mode in your React app, using TailwindCSS and lucide-react for a smooth user experience.
Best,
Guillaume Duhan