How to Add a Dark Mode Toggle to Any Website — CSS Variables and localStorage

Learn how to add a professional dark/light mode toggle to your website using CSS custom properties, a single data attribute, smooth transitions, OS preference detection, and localStorage persistence.

📅 2026-06-262 min read📚 Ebook #12

The Clean Way to Implement Dark Mode

There are many ways to add dark mode — but most beginners do it wrong. The right way uses CSS custom properties (variables) and a single data-theme attribute on the <html> element. Change one attribute, and your entire website changes theme instantly.

Step 1 — Define CSS Variables

/* Light theme — default */
:root {
  --bg:   #ffffff;
  --text: #1a1a1a;
  --card: #f5f5f5;
}

/* Dark theme — activated by data attribute */
[data-theme="dark"] {
  --bg:   #0d0d0d;
  --text: #e8e8e8;
  --card: #1a1a1a;
}

/* Use variables everywhere */
body  { background: var(--bg);   color: var(--text); }
.card { background: var(--card); }

Step 2 — Add Smooth Transitions

Without transitions, the theme change is an instant flash. One CSS rule fixes this:

*, *::before, *::after {
  transition:
    background-color 0.3s ease,
    color 0.3s ease,
    border-color 0.3s ease;
}

Step 3 — The Toggle JavaScript

function applyTheme(theme) {
  if (theme === 'dark') {
    document.documentElement.setAttribute('data-theme', 'dark');
  } else {
    document.documentElement.removeAttribute('data-theme');
  }
}

document.getElementById('toggle').addEventListener('click', () => {
  const isDark   = document.documentElement.getAttribute('data-theme') === 'dark';
  const newTheme = isDark ? 'light' : 'dark';
  applyTheme(newTheme);
  localStorage.setItem('theme', newTheme); // Remember choice
});

Step 4 — Detect OS Preference

function initTheme() {
  const saved = localStorage.getItem('theme');
  if (saved) { applyTheme(saved); return; }

  // Fall back to OS preference
  const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
  applyTheme(prefersDark ? 'dark' : 'light');
}

initTheme(); // Run on page load

The priority order is: saved preference → OS setting → light (default).

This is a preview. The full ebook includes the animated pill toggle button CSS, a complete demo page showing dark mode applied to inputs, cards, and forms, and a step-by-step guide for adding dark mode to an existing website.

Ready to Build This Yourself?

This article is a preview. The full ebook has complete code, detailed explanations, troubleshooting tips, and bonus sections — all in a downloadable PDF.

Buy Full Ebook — $1.50 in $YFIN
Pay with $YFIN on BNB Smart Chain · 30% burned permanently