For the last year or so I have been using TailwindCSS. It's great. It's truly a breath of fresh air from plain CSS. For me, someone who prefers to write code than spend hours bloating out my code base, it is a dream.
One of the first things I played with in Tailwind is the ability to create and manage dark mode. The docs are pretty good at describing the different ways to achieve dark mode in Tailwind. To get started, I used the system preferred mode. Simple enough. The next step is to create a button to toggle dark mode on or off. I spent the last few hours doing this and here's what I learned...
Firstly, my setup - Next.JS 13 with the pages router.
The first issue I ran into was where to place the dark
class at a top level so every child component can adjust accordingly. I started by placing it in the _app
file, and setting the background on the <body>
tag - no bueno. I was unable to toggle dark
on/off.
So, I created a context - DarkModeContext
. I placed this context around the main Html tag. Again, no bueno. NextJS renders the context in _app
on the server. I don't want to lose server side rendering so best to not force _app
to render on the client.
Hmm. Okay. What to do. What if I use the context I created? If I can add/remove the dark mode toggle from the main Html element then that will achieve what I want. By doing this, I can manage the dark mode state in one place, make it available to the whole app, and toggle dark mode on/off. Perfect!
const DarkModeContextProvider = ({ children }: Props) => {
const [darkMode, setDarkMode] = useState(false);
useEffect(() => {
const toggleDarkMode = () => {
const rootElement = document.documentElement;
rootElement.classList.toggle("dark", darkMode);
};
toggleDarkMode();
}, [darkMode]);
return (
<DarkModeContext.Provider
value={{
darkMode,
setDarkMode,
}}
>
{children}
</DarkModeContext.Provider>
);
};
Thanks for reading about a lovely little dark mode toggle!