How To Create a Dark Mode Toggle
Learn how to add a button that switches your page between light and dark colours.
Step 1: Colours as CSS Variables
Store your colours in CSS variables on :root. Then define new values for them when the <body> has a dark class.
Example
:root {
--bg: #ffffff;
--text: #1f2937;
--card: #f3f4f6;
}
body.dark {
--bg: #111827;
--text: #f9fafb;
--card: #1f2937;
}
body { background: var(--bg); color: var(--text); }
.card { background: var(--card); }var(--bg) reads the variable. Because every colour uses a variable, one class change recolours the whole page.
Step 2: The Button
Example
<button id="themeBtn">Switch to dark mode</button>Step 3: The JavaScript
The script toggles the dark class, updates the button text, and saves the choice in localStorage so it is remembered next time.
Example
const btn = document.getElementById("themeBtn");
function applyTheme(isDark) {
document.body.classList.toggle("dark", isDark);
btn.innerHTML = isDark ? "Switch to light mode" : "Switch to dark mode";
}
btn.addEventListener("click", function () {
const isDark = !document.body.classList.contains("dark");
applyTheme(isDark);
try { localStorage.setItem("theme", isDark ? "dark" : "light"); } catch (e) {}
});classList.toggle("dark", isDark) adds the class when isDark is true and removes it when false.
Saving can fail in private browsing windows, so the localStorage lines are wrapped in try ... catch. The page still works, it just will not remember the choice.
The Complete Example
Example
<!DOCTYPE html>
<html>
<head>
<style>
:root { --bg: #ffffff; --text: #1f2937; --card: #f3f4f6; --accent: #059669; }
body.dark { --bg: #111827; --text: #f9fafb; --card: #1f2937; --accent: #34d399; }
body { background: var(--bg); color: var(--text); font-family: Arial, sans-serif; padding: 20px; transition: background 0.3s, color 0.3s; }
.card { background: var(--card); padding: 16px; border-radius: 10px; margin-top: 16px; }
h1 { color: var(--accent); }
#themeBtn { background: var(--accent); color: var(--bg); border: none; padding: 10px 16px; border-radius: 6px; font-size: 15px; cursor: pointer; }
</style>
</head>
<body>
<h1>Bilal's Blog</h1>
<button id="themeBtn">Switch to dark mode</button>
<div class="card">
<h2>Studying at night?</h2>
<p>Dark mode is easier on the eyes in a dark room.</p>
</div>
<script>
const btn = document.getElementById("themeBtn");
function applyTheme(isDark) {
document.body.classList.toggle("dark", isDark);
btn.innerHTML = isDark ? "Switch to light mode" : "Switch to dark mode";
}
let saved = null;
try { saved = localStorage.getItem("theme"); } catch (e) {}
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
applyTheme(saved ? saved === "dark" : prefersDark);
btn.addEventListener("click", function () {
const isDark = !document.body.classList.contains("dark");
applyTheme(isDark);
try { localStorage.setItem("theme", isDark ? "dark" : "light"); } catch (e) {}
});
</script>
</body>
</html>Try it Yourself »Following the System Setting
matchMedia("(prefers-color-scheme: dark)") checks whether the visitor's phone or computer is set to dark mode. The example uses it as the starting theme when nothing has been saved yet.
| Step | What the page does |
|---|---|
| 1 | Looks for a saved choice in localStorage |
| 2 | If none, follows the system setting |
| 3 | On click, switches and saves the new choice |
Exercise
Exercise
Why are the colours stored in CSS variables?
