Auto
Light
Dark
How to use?

πŸŒ— How to Use the Theme Switcher

This theme switcher system allows users to toggle between Light Mode, Dark Mode, and Auto Mode (which follows the system's color preference). Here's how to properly implement and use the required HTML attributes and classes.

🏷️ HTML Attributes

To make the switcher work, each button (or clickable element) must include two attributes:

  • theme-role="toggle"
    This marks the element as a theme toggle button. Without it, the script will ignore the element.
  • theme-label="light" / "dark" / "auto"
    This defines which theme the button activates:
    • light: Forces light theme
    • dark: Forces dark theme
    • auto: Follows the user's operating system preference

You can assign these attributes to any HTML element (buttons, links, divs, etc.).

✨ Active State Handling

When a user selects a theme:

  • The chosen theme is applied to the <body> using a class (u-theme-light or u-theme-dark).
  • The selected button automatically receives the class theme-active, allowing you to visually highlight the active choice.
  • If the user selects Auto, the script applies the correct theme based on the system setting and dynamically updates it if the system preference changes later.

🧠 Theme Logic Overview

  • If the user selects Light or Dark, their preference is saved in localStorage, and the corresponding class is added to <body>.
  • If the user selects Auto, no preference is saved. Instead, the system preference is used (and updated in real time if the system theme changes).
  • On page load, the script checks the saved preference or defaults to auto if nothing is stored.

🏁 Required Classes

Your CSS should include styling rules that correspond to two body classes:

  • .u-theme-light β†’ Applied when light theme is active
  • .u-theme-dark β†’ Applied when dark theme is active

You are free to design each theme however you like. The presence of these classes is what triggers the visual change.

🎯 Summary

To integrate this theme switcher:

  • Add theme-role="toggle" to all theme buttons.
  • Use theme-label to define each button’s function (light, dark, or auto).
  • Style .u-theme-light and .u-theme-dark in your CSS for the visual appearance.
  • Optionally style .theme-active to highlight the selected option.
  • The script handles saving preferences and adapting to system changes automatically.
Give me the code
<script>
// Detects if the user prefers dark mode at the system level
const darkThemeMq = window.matchMedia("(prefers-color-scheme: dark)");

/**
 * Applies the selected theme to the <body> element
 * @param {string} theme - "dark", "light", or "auto"
 */
function applyTheme(theme) {
  const body = document.body;
  // Remove any existing theme class
  body.classList.remove("u-theme-dark", "u-theme-light");

  if (theme === "dark") {
    // Apply dark theme
    body.classList.add("u-theme-dark");
  } else if (theme === "light") {
    // Apply light theme
    body.classList.add("u-theme-light");
  } else {
    // Auto: follow the system's preferred color scheme
    if (darkThemeMq.matches) {
      body.classList.add("u-theme-dark");
    } else {
      body.classList.add("u-theme-light");
    }
  }
}

/**
 * Sets the theme based on user preference saved in localStorage.
 * If no preference is saved, auto mode is applied.
 */
function setTheme() {
  // Remove the active class from all toggle buttons
  document.querySelectorAll('[theme-role=toggle]').forEach(el => {
    el.classList.remove("theme-active");
  });

  // Get the saved theme from localStorage
  const savedTheme = localStorage.getItem("theme");

  if (!savedTheme) {
    // Default to auto mode if no theme is saved
    document.querySelector("[theme-label=auto]")?.classList.add("theme-active");
    applyTheme("auto");
  } else {
    // Apply the saved theme and mark the correct button as active
    document.querySelector(`[theme-label="${savedTheme}"]`)?.classList.add("theme-active");
    applyTheme(savedTheme);
  }
}

// Add click event listeners to all theme toggle buttons
document.querySelectorAll('[theme-role=toggle]').forEach(button => {
  button.addEventListener("click", function () {
    const selectedTheme = this.getAttribute("theme-label");

    if (selectedTheme === "auto") {
      // Remove saved theme to fallback to system preference
      localStorage.removeItem("theme");
    } else {
      // Save the selected theme
      localStorage.setItem("theme", selectedTheme);
    }

    setTheme();
  });
});

// Listen for system color scheme changes if "auto" mode is active
darkThemeMq.addEventListener("change", () => {
  if (!localStorage.getItem("theme")) {
    setTheme();
  }
});

// Initialize the theme on page load
setTheme();
</script>
Built by Nisium