Day and Night: The Tiny Switch That Changes the Whole Site
A friendly, technical walkthrough of how the day/night theme switch works, plus a big version you can play with.
The day and night switch looks like a small UI detail, but it is doing a lot of work. It decides which colors the entire site uses, how the background feels, and whether the text is bright or calm. This post explains the switch in plain terms and shows the real implementation choices behind it.
If you are not technical, this is still for you. Think of it like a light switch in a house: the wiring is hidden, but the behavior is clear. We will walk through the wiring in a friendly way, then let you try a bigger version of the switch inside the post.
What the switch actually changes
The key idea is simple: the page keeps two color palettes ready. The switch just tells the page which palette to use.
In practice, the website puts a single attribute on the root HTML element, like this:
<html data-theme="light">
When you flip the switch, that attribute becomes dark. Everything else follows.
Why does one attribute change so much? Because the colors are defined as variables. Here is the same idea simplified:
:root {
--bg: #ffffff;
--text: #0b0c0e;
--surface: #f8fafc;
--accent: #6366f1;
}
[data-theme='dark'] {
--bg: #0b0c0e;
--text: #f8fafc;
--surface: #1e293b;
--accent: #818cf8;
}
Every part of the UI is styled with those variables. So the switch is not repainting each component by hand. It is simply picking a different set of variables for the entire site.
The switch itself (the visible part)
The button is a normal HTML button. It just looks fancy because of its animation. The core logic is tiny: decide if we are in dark mode, then flip to the opposite.
Here is the essential idea, simplified to be readable:
const isDark = (theme ?? resolvedTheme) === 'dark'
<button onClick={() => setTheme(isDark ? 'light' : 'dark')}>
Toggle
</button>
That is the wiring. The rest is presentation: a rounded track, a circular knob, and two icons that fade and rotate as the knob moves.
To make the animation feel smooth, both the sun and moon icons are rendered at the same time. One fades out while the other fades in. The knob slides across the track with a gentle easing curve, so the motion feels physical instead of robotic.
Try the large prototype
The switch below is the same logic as the small one in the nav bar. I just scaled it up so you can see the motion and the color shift clearly. Tap it a few times and notice how the site background and text colors flip instantly.
Why it does not flicker
If you ever built a theme toggle, you have probably seen a quick flash of the wrong theme. That happens because the server does not know your preference yet. It sends the page, then the browser loads your saved choice and flips.
This site avoids the worst of that flash by waiting to render the switch until it is mounted on the client. The idea is: do not show the toggle until we know the actual theme.
Here is the tiny pattern that makes it work:
const [mounted, setMounted] = useState(false)
useEffect(() => setMounted(true), [])
if (!mounted) return null
That is not glamorous, but it is the difference between a switch that feels professional and one that feels glitchy.
Remembering your choice
The switch does not just flip the palette once. It remembers your preference for the next visit. That memory lives in the browser (using local storage), and it can also respect your system preference if you have one.
If your computer is set to dark mode at night and light mode during the day, the site can follow that automatically. If you flip the switch manually, the site respects your choice and sticks to it.
You do not need to think about that storage logic. The theme library handles it, and the switch only cares about one decision: light or dark.
The design goal behind the animation
A good switch should do two things at once:
- Tell you that something changed.
- Feel fast and confident, not distracting.
That is why the knob moves in about 300 to 500 milliseconds. Short enough to feel responsive, long enough to feel intentional. The icons rotate just a little so the change is visible even if you are not staring at the background. And the color transition is handled by the CSS variables, which makes the whole site feel like it is breathing instead of blinking.
If you are reading this on a phone, the switch should still feel friendly. The size and spacing are big enough to tap, and the animation is still visible even on a small screen.
The big takeaway
The day and night switch is not magic. It is one attribute, a set of CSS variables, and a small bit of state logic. The power comes from the architecture: design everything around shared variables, then let the switch change the variables in one move.
That is a pattern you can reuse in any project. It keeps the code simple, the UI consistent, and the user experience smooth.
If you want to see the exact implementation, check out the theme-toggle component and the CSS variables in the global stylesheet. The rest is just polish.