Light / Dark Mode Toggle with HTML, CSS & JavaScript

20 DAYS 20 PROJECT CHALLENGE

Day #15

Project Overview

A simple and modern Light/Dark mode theme switcher built using CSS variables and LocalStorage.
With a single click, the user can switch the entire websiteโ€™s theme, and the preference is saved so the site loads in the chosen theme even after refresh or reopening the browser.

This project helps you understand:

  • How to use CSS variables for global theme colors.
  • How to toggle theme classes with JavaScript.
  • How to save & load user preferences using LocalStorage.
  • How to update UI icons and transitions for a smooth effect.

Key Features

  • One-click theme toggle (light โ†” dark).
  • Smooth color transitions.
  • Theme icon change (sun/moon).
  • Persistent theme using LocalStorage.
  • Clean UI + responsive layout.
  • Uses CSS variables to maintain entire site theme.

HTML Code

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1"/>
  <title>Day 15 — Light/Dark Mode Toggle</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <main class="card" role="main">
    <header class="head">
      <h1>Day 15: Light / Dark Mode Toggle</h1>
      <p class="lead">Switch themes with one click. Your preference is saved.</p>

      <button id="themeToggle" class="theme-btn" aria-label="Toggle Theme">
        <span id="themeIcon">๐ŸŒ™</span>
      </button>
    </header>

    <section>
      <p>
        This is a demo of a light/dark theme switcher using CSS variables and LocalStorage.
        Click on the moon/sun icon above to change the theme.
      </p>
    </section>

    <details>
      <summary>How it works (short)</summary>
      <p class="small">
        The website uses a <code>data-theme</code> attribute on the HTML tag.
        CSS variables define the theme colors. JavaScript toggles the attribute
        and saves the choice in LocalStorage. On page load, the saved theme is applied.
      </p>
    </details>
  </main>

  <script src="script.js"></script>
</body>
</html>

CSS Code

/* THEME VARIABLES */
:root {
  --bg: #ffffff;
  --text: #1e293b;
  --card-bg: #f1f5f9;
  --accent: #7c3aed;
}

html[data-theme="dark"] {
  --bg: #002252;
  --text: #e2e8f0;
  --card-bg: #1e293b;
  --accent: #c084fc;
}

html, body {
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: Inter, system-ui, sans-serif;
  margin: 0;
  transition: background 0.3s ease, color 0.3s ease;
}

/* CARD */
.card {
  width: min(700px, 92%);
  margin: 40px auto;
  background: var(--card-bg);
  padding: 22px;
  border-radius: 14px;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
  transition: background 0.3s ease;
}

.head {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.lead {
  margin-top: -10px;
  font-size: 14px;
  opacity: 0.8;
}

/* TOGGLE BUTTON */
.theme-btn {
  background: var(--accent);
  border: none;
  color: white;
  font-size: 22px;
  border-radius: 50%;
  width: 44px;
  height: 44px;
  cursor: pointer;
  box-shadow: 0 4px 14px rgba(124, 58, 237, 0.4);
  transition: transform 0.2s ease;
}

.theme-btn:hover {
  transform: scale(1.1);
}

.small {
  font-size: 13px;
  opacity: 0.8;
}

Javascript Code

// Day 15: Light/Dark Mode Toggle
// Uses data-theme attribute + LocalStorage

const themeToggle = document.getElementById('themeToggle');
const themeIcon = document.getElementById('themeIcon');

// Load saved theme from LocalStorage
const savedTheme = localStorage.getItem('theme');

if (savedTheme) {
  document.documentElement.setAttribute('data-theme', savedTheme);
  themeIcon.textContent = savedTheme === 'dark' ? 'โ˜€๏ธ' : '๐ŸŒ™';
}

// Toggle theme
themeToggle.addEventListener('click', () => {
  const current = document.documentElement.getAttribute('data-theme');
  const newTheme = current === 'dark' ? 'light' : 'dark';

  // Apply new theme
  document.documentElement.setAttribute('data-theme', newTheme);

  // Save in LocalStorage
  localStorage.setItem('theme', newTheme);

  // Update icon
  themeIcon.textContent = newTheme === 'dark' ? 'โ˜€๏ธ' : '๐ŸŒ™';
});
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

Related Projects

Day 13 : Currency Converter

Converts one currency to another using real-time exchange rates.

Concepts: API fetch, DOM updates.

Day 17 : Clipboard Copy Tool

Click a button to copy text to the clipboard.

Concepts: Clipboard API, DOM events.

Day 18 : Text-to-Speech Converter

Converts entered text into speech.

Concepts: Web Speech API.