The perfect mild/darkish mode theme toggle in JavaScript

Learn to construct The Final Theme Toggle™️ to your web site utilizing JavaScript, CSS customized properties, native storage and system settings. No framework required!

I used to disagree with mild and darkish mode toggles. “The toggle is the consumer system preferences!” I’d exclaim naïvely, opting to let the prefers-color-scheme CSS media question management the theming on my private web site. No toggle. No selection. 🫠

I’ve been a darkish mode consumer ever because it turned a factor. However not too long ago, I’ve most popular to make use of some web sites and instruments in mild mode — together with my private web site — while protecting my system settings firmly at the hours of darkness. I wanted a toggle. I wanted a selection! And so does everybody else.

On this publish I’ll present you ways I constructed The Final Theme Toggle™️ for my web site in JavaScript that:

  1. Shops and retrieves a theme desire in native browser storage,
  2. Falls again to consumer system preferences,
  3. Falls again to a default theme if not one of the above are detected.

TL;DR: right here’s the code on CodePen.

Add a knowledge attribute to your HTML tag

In your HTML tag, add a knowledge attribute akin to data-theme and provides it a default worth of sunshine or darkish. Up to now I’ve used the customized attribute color-mode as an alternative of a knowledge attribute (e.g. color-mode="mild"). Whereas this works, it’s not classed as legitimate HTML and I can’t discover any documentation on it! Any perception on that is a lot appreciated. 😅

<html lang="en" data-theme="mild">
    <!-- all different HTML -->
Enter fullscreen mode

Exit fullscreen mode

Configure theming by way of [CSS custom properties

In your CSS, configure your theme colours via CSS custom properties (or variables) under each value for the data-theme attribute. Note that you don’t necessarily need to use :root in combination with data-theme, but it’s useful for global properties that don’t change with the theme (shown in the example below). Learn more about the :root CSS pseudo-class on MDN.

:root {
  --grid-unit: 1rem;
  --border-radius-base: 0.5rem;

[data-theme="light"] {
  --color-bg: #ffffff;
  --color-fg: #000000;

[data-theme="dark"] {
  --color-bg: #000000;
  --color-fg: #ffffff;

/* instance use of CSS customized properties */
physique {
  background-color: var(--color-bg);
  coloration: var(--color-fg);
Enter fullscreen mode

Exit fullscreen mode

Swap the data-theme attribute manually in your HTML tag, and also you’ll see your theme change already (so long as you’re utilizing these CSS properties to type your components)!

Construct a toggle button in HTML

Add an HTML button to your web site header, or wherever you want the theme toggle. Add a data-theme-toggle attribute (we’ll use this to focus on the button in JavaScript later), and an aria-label in case you’re planning to make use of icons in your button (akin to a solar and moon to signify mild and darkish mode respectively) in order that display readers and assistive know-how can perceive the aim of the interactive button.

    aria-label="Change to mild theme"
  >Change to mild theme (or icon right here)</button>
Enter fullscreen mode

Exit fullscreen mode

Calculate theme setting on web page load

Right here’s the place we’ll calculate the theme setting primarily based on what I name the “desire cascade”.

Get theme desire from native storage

We will use the localStorage property in JavaScript to avoid wasting consumer preferences in a browser that persist between periods (or till it’s manually cleared). In The Final Theme Toggle™️, the saved consumer desire is crucial setting, so we’ll search for that first.

On web page load, use localStorage.getItem("theme") to verify for a beforehand saved desire. Later within the publish, we’ll replace the theme worth every time the toggle is pressed. If there’s no native storage worth, the worth can be null.

// get theme on web page load

// set theme on button press
localStorage.setItem("theme", newTheme);
Enter fullscreen mode

Exit fullscreen mode

Detect consumer system settings in JavaScript

If there’s no saved theme desire in localStorage, we’ll detect the consumer’s system settings utilizing the window.matchMedia() technique by passing in a media question string. You’ll solely must calculate one setting for the needs of the desire cascade, however the code beneath exhibits how one can detect mild or darkish system settings.

const systemSettingDark = window.matchMedia("(prefers-color-scheme: darkish)");
// or
const systemSettingLight = window.matchMedia("(prefers-color-scheme: mild)");
Enter fullscreen mode

Exit fullscreen mode

window.matchMedia() returns a MediaQueryList containing the media question string you requested, and whether or not it matches (true/false) the consumer system settings.

  matches: true,
  media: "(prefers-color-scheme: darkish)",
  onchange: null
Enter fullscreen mode

Exit fullscreen mode

Fall again to a default theme

Now you’ve entry to a localStorageworth and system settings by way of window.matchMedia(), you may calculate the popular theme setting utilizing the desire cascade (native storage, then system setting), and fall again to a default theme of your selection (which must be the default theme you specified in your HTML tag earlier).

We’ll run this code on web page load to calculate the present theme setting.

perform calculateSettingAsThemeString({ localStorageTheme, systemSettingDark }) {
  if (localStorageTheme !== null) {
    return localStorageTheme;

  if (systemSettingDark.matches) {
    return "darkish";

  return "mild";

const localStorageTheme = localStorage.getItem("theme");
const systemSettingDark = window.matchMedia("(prefers-color-scheme: darkish)");

let currentThemeSetting = calculateSettingAsThemeString({ localStorageTheme, systemSettingDark });
Enter fullscreen mode

Exit fullscreen mode

Add an occasion listener to the toggle button

Subsequent, we’ll arrange an occasion listener to modify the theme when the button is pressed. Goal the button within the DOM utilizing the information attribute (data-theme-toggle) we added earlier, and add an occasion listener to the button on click on. The instance beneath is sort of verbose, and also you would possibly need to summary out a number of the performance beneath into utility features (which I’ve accomplished in the instance on CodePen). Let’s stroll this via:

  1. Calculate the brand new theme as a string
  2. Calculate and replace the button textual content (in case you’re utilizing icons in your button, here is the place you will make the change)
  3. Replace the aria-label on the button
  4. Swap the data-theme attribute on the HTML tag
  5. Save the brand new theme desire in native storage
  6. Replace the currentThemeSetting in reminiscence
// goal the button utilizing the information attribute we added earlier
const button = doc.querySelector("[data-theme-toggle]");

button.addEventListener("click on", () => {
  const newTheme = currentThemeSetting === "darkish" ? "mild" : "darkish";

  // replace the button textual content
  const newCta = newTheme === "darkish" ? "Change to mild theme" : "Change to darkish theme";
  button.innerText = newCta;  

  // use an aria-label in case you are omitting textual content on the button
  // and utilizing solar/moon icons, for instance
  button.setAttribute("aria-label", newCta);

  // replace theme attribute on HTML to modify theme in CSS
  doc.querySelector("html").setAttribute("data-theme", newTheme);

  // replace in native storage
  localStorage.setItem("theme", newTheme);

  // replace the currentThemeSetting in reminiscence
  currentThemeSetting = newTheme;
Enter fullscreen mode

Exit fullscreen mode

To verify localStorage is being up to date, open up your dev instruments, navigate to the Utility tab, broaden Native Storage and choose your website. You’ll see a key:worth checklist; search for theme and click on the button to observe it replace in actual time. Reload your web page and also you’ll see the theme desire preserved!

Browser window with dev tools open on application tab. Local storage on whitepanther dot com is selected, showing a key value pair stored in the browser of theme light.

Put all of it collectively!

  1. Now you can construct your very personal Final Theme Toggle™️ by:
  2. Utilizing CSS customized properties to specify totally different theme colors, switched by way of a knowledge attribute in your HTML tag
  3. Utilizing an HTML button to energy the toggle
  4. Calculating the popular theme on web page load by utilizing the desire cascade (native storage > system settings > fallback default theme)
  5. Switching the theme on click on of the toggle button, and storing the consumer desire within the browser for future visits

Right here’s the complete CodePen, and you’ll take a look at the working model on my private web site. Completely happy toggling!

Leave a Reply

Your email address will not be published. Required fields are marked *