Day 08: Theme Toggle + Caching Data
Add a light/dark mode toggle and save the choice.
JavaScript focus
- toggling a class on body
- checking saved preference
- local storage
- updating accessible labels
Nice extras
- use system preference on first visit
- animated icon swap
- persist toggle button text
MDN prep
- localStorage
- matchMedia
- classList.toggle
- JSON.stringify
- JSON.parse
- JSON.stringify + JSON.parse not required unless storing more data
Theme Toggle / Dark Mode
The HTML
<section class="section theme_toggle">
<h2 class="secondary_heading">Theme Toggle / <span id="toggle_title">Dark</span> Mode</h2>
<div class="toggle_container">
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" class="moon_icon" viewBox="0 0 512 512"><path d="M264 480A232 232 0 0132 248c0-94 54-178.28 137.61-214.67a16 16 0 0121.06 21.06C181.07 76.43 176 104.66 176 136c0 110.28 89.72 200 200 200 31.34 0 59.57-5.07 81.61-14.67a16 16 0 0121.06 21.06C442.28 426 358 480 264 480z"/></svg>
<button type="button" class="button toggle_button" aria-label="Dark Mode" id="theme-toggle-button" aria-pressed="false">
<div class="animated_toggle"></div>
</button>
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" class="sun_icon" viewBox="0 0 512 512"><path d="M256 118a22 22 0 01-22-22V48a22 22 0 0144 0v48a22 22 0 01-22 22zM256 486a22 22 0 01-22-22v-48a22 22 0 0144 0v48a22 22 0 01-22 22zM369.14 164.86a22 22 0 01-15.56-37.55l33.94-33.94a22 22 0 0131.11 31.11l-33.94 33.94a21.93 21.93 0 01-15.55 6.44zM108.92 425.08a22 22 0 01-15.55-37.56l33.94-33.94a22 22 0 1131.11 31.11l-33.94 33.94a21.94 21.94 0 01-15.56 6.45zM464 278h-48a22 22 0 010-44h48a22 22 0 010 44zM96 278H48a22 22 0 010-44h48a22 22 0 010 44zM403.08 425.08a21.94 21.94 0 01-15.56-6.45l-33.94-33.94a22 22 0 0131.11-31.11l33.94 33.94a22 22 0 01-15.55 37.56zM142.86 164.86a21.89 21.89 0 01-15.55-6.44l-33.94-33.94a22 22 0 0131.11-31.11l33.94 33.94a22 22 0 01-15.56 37.55zM256 358a102 102 0 11102-102 102.12 102.12 0 01-102 102z"/></svg>
</div>
</section>
The JavaScript
function initThemeToggle() {
const body = document.body;
const root = document.querySelector(".theme_toggle");
if (!root) return;
const title = root.querySelector("#toggle_title");
const toggle = root.querySelector(".toggle_button");
// get saved theme on page load
const savedTheme = localStorage.getItem("theme");
if (savedTheme === "light") {
body.classList.add("light_mode");
title.textContent = "Light";
} else {
title.textContent = "Dark";
}
toggle.addEventListener("click", () => {
const isActiveToggle = body.classList.toggle("light_mode");
if (isActiveToggle) {
title.textContent = "Light";
localStorage.setItem("theme", "light");
} else {
title.textContent = "Dark";
localStorage.setItem("theme", "dark");
}
});
}
initThemeToggle();