The problem
A dark mode toggle sounds like it needs a framework or a build step, but for a static site it’s really just one data attribute, a CSS variable swap, and a few lines of JavaScript to remember the choice.
Expected outcome
By the end of this guide you will have a working toggle that switches your site’s colors, remembers the visitor’s choice across visits, and respects their OS/browser preference the first time they arrive.
Requirements and costs
- Any static site (plain HTML/CSS/JS).
- Cost: free.
Step-by-step implementation
- Download the starter from the link below.
- Add
dark-mode.jsto your site and include it with<script src="dark-mode.js"></script>near the end of your page. - Add a button with
id="toggle"anywhere on the page — the script wires itself to it automatically. - Define your colors as CSS variables, with dark values under a
[data-theme="dark"]selector::root { --bg: #ffffff; --fg: #111111; } [data-theme="dark"] { --bg: #121212; --fg: #f0f0f0; } body { background: var(--bg); color: var(--fg); }
A real example
Click the toggle and the page switches instantly; reload the page and it’s still dark, because the choice was saved. A first-time visitor whose browser/OS is already set to dark mode sees the dark version immediately, with no toggle click needed, until they explicitly choose otherwise.
Verification and troubleshooting
What we tested, on 5 October 2026 (record TNT-TEST-2026-10-05-009): loaded the demo in a real browser, clicked the toggle (confirmed data-theme became “dark” and the choice was saved to localStorage), then reloaded the page from scratch and confirmed data-theme was still “dark” — proving the persistence actually works across a real navigation, not just within one page session.
Troubleshooting:
- The toggle does nothing. Check the script is loaded AFTER the button exists in the HTML (at the end of
<body>, as shown), or wrap the script’s code in aDOMContentLoadedlistener if you need it in the<head>. - It flashes light mode for a split second before switching to dark. That’s the script running after the page has already painted; for a flash-free experience, inline a tiny blocking script in
<head>that reads localStorage and sets the attribute before the rest of the page renders. - It ignores the visitor’s OS preference. That only applies when they haven’t made an explicit choice yet — once they’ve clicked the toggle once, their saved choice always wins over the OS preference, by design.
Limitations and alternatives
This assumes your whole page’s colors are expressed as CSS variables; a page with hardcoded colors scattered through its CSS needs those converted to variables first. For sites that already use a CSS framework with its own dark mode system (many do now), check whether you already have this before adding a second one.
Free resources
The download contains the script and a working demo page showing the exact pattern.
Download the dark mode toggle starter (ZIP, 1 KB)
Is there a paid version?
Not yet. This is the complete method. TNT Review has sold nothing to date and has no checkout, so any price we discuss in future should be read as a hypothesis, not an offer.