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.It allows users to switch between light mode and dark mode with a single click. The complete website changes its background, text, card, and accent colors based on the selected theme.
CSS variables are used to store all the colors for each theme, allowing us to use one block of code for all elements and maintain a consistent look and feel. JavaScript is used to toggle between the themes and change the icon to the moon or sun. The theme is saved in the LocalStorage so that the website knows the user’s preference and loads it on the next visit.
Key Features
- One-Click Theme Toggle: Users can toggle between light and dark themes by clicking a toggle button. The selected theme is applied to the whole webpage.
- Light and Dark Themes: The app offers two visual themes with different background, text, cards, and accent colors. Users can select their preferred theme.
- CSS Variables: The project uses CSS variables to store the colors for each theme. By changing the value of a variable, all elements on a webpage whose styles are dependent on it automatically update their colors.
- Smooth Transition: CSS transitions make the changes in colors smooth so that the light and dark themes are not changed abruptly.
- Dynamic Theme Icon: A toggle button, whose icon changes between the moon and sun, changes between dark and light themes when clicked by a user.
- LocalStorage: The theme selected by a user is stored in the browser by LocalStorage. Hence, a user can keep using the selected theme even after refreshing or closing the tab.
- Auto Detect Saved Theme: By default, the application is set to use the theme saved by a user. Hence, when the web page reloads, the app detects the theme and uses it.
- Responsive Web Design: The app has been built using a responsive web design that works well on desktops, tablets, and mobile devices.
- Simple and Clean: The project focuses on a minimal interface with a clear theme toggle button, making the functionality easy to understand and use.
- Easy Customization: Developers can customize the app by editing the CSS variables, animations, transitions, toggle button, and other settings.
What You'll Learn
- Understand how CSS variables can be used to manage website colors.
- Learn how to create separate styles for light and dark themes.
- Practice changing HTML attributes using JavaScript.
- Understand how
data-themeattributes can control CSS styles. - Learn how to use
setAttribute()andgetAttribute(). - Practice handling button click events.
- Learn how to save user preferences using
localStorage.setItem(). - Practice retrieving saved values using
localStorage.getItem(). - Understand how to update text and icons dynamically.
- Learn how CSS transitions create smooth theme changes.
HTML Code
HTML creates the basic structure of the Light / Dark Mode Toggle project. The main content is placed inside the .card container, which holds the project heading, description, theme toggle button, and additional information. Inside the header, the #themeToggle button is used to switch between the light and dark themes. This button contains a <span> element with the ID themeIcon, which displays the moon or sun icon. JavaScript changes this icon depending on the currently active theme.
The content section provides information about how the theme switcher works, while the <details> element contains an additional explanation for users. The style.css file is linked inside the <head> section so CSS can control the appearance of both themes and the script.js file is linked at the bottom of the <body>, allowing JavaScript to access the toggle button, change the data-theme attribute, update the icon, and save the selected theme in LocalStorage.
<!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
CSS controls the appearance of both the light and dark themes. The :root selector defines the default CSS variables for the light theme, including the background color, text color, card background, and accent color. The html[data-theme="dark"] selector defines different values for the same CSS variables when dark mode is active. Because the rest of the CSS uses values such as var(--bg) and var(--text), changing the data-theme attribute automatically updates the appearance of multiple elements across the webpage.
The html and body selectors use the theme variables for the background and text colors. CSS transitions are added so the color changes appear smoothly when users switch themes and the .card class styles the main content area with a responsive width, padding, rounded corners, and a shadow. The .theme-btn class styles the circular theme button, while the hover effect slightly increases its size to provide visual feedback when users interact with it.
/* 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
JavaScript handles the theme switching and preference-saving functionality. First, document.getElementById() selects the #themeToggle button and the #themeIcon element. It uses localStorage.getItem('theme') to check whether the user has previously selected and saved a theme. If a saved value exists, JavaScript applies it to the <html> element using setAttribute('data-theme', savedTheme).
A click event listener is added to the theme toggle button. When the user clicks the button, JavaScript checks the current value of the data-theme attribute and switches it between light and dark. After selecting the new theme, the code applies the updated value to the HTML element and saves it using localStorage.setItem('theme', newTheme). Finally, the moon or sun icon is updated so users can clearly see which theme can be switched to next.
// 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' ? '☀️' : '🌙';
});
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.