Dark mode switch

Posted March 19, 2022 by Priyadarshan Giri ‐ 3 min read

Switch theme using css variables

I wanted a dead simple way to switch themes in my personal website (which is not up at the time of this post).

Google showed me a lot of results, but most of the examples were based on switching classes. It is an effective way, but as the complexity of the site theme increases, it becomes confusing to keep up with the code (for me at least).

So, I looked for some other ways and found out we can directly change the values of css variables.

Theme is just a group of colors. So, we can start by defining the colors in a javascript map, like:

const darkThemeColors = new Map([
  ["primary", "#68e0cf"],
  ["secondary", "#585d65"],
  ["text", "#edf8f4"],
  ["background", "#373b40"],
]);

const lightThemeColors = new Map([
  ["primary", "#309485"],
  ["secondary", "#a7adcb"],
  ["text", "#000"],
  ["background", "#d3d3d3"],
]);

We also define variables in root of css using :root{} selector.

:root {
  --color-primary: #68e0cf;
  --color-secondary: #585d65;
  --color-text: #edf8f4;
  --color-background: #373b40;
}

This is kind of repetitive. So, will come up with a better way to do this.

Then we need a checkbox to toggle between the two themes.

<div class="toggle-dark-mode">
  <input type="checkbox" id="toggle" onchange="toggleDarkMode()" checked />
  <label for="toggle" class="toggle-label"></label>
</div>

Finally a function to handle the change in theme using setProperty in document style.

function toggleDarkMode() {
  let rootVariables = document.querySelector(":root");

  let darkMode = document.getElementById("toggle");
  if (darkMode.checked) {
    // dark theme

    rootVariables.style.setProperty(
      "--color-primary",
      darkThemeColors.get("primary")
    );
    rootVariables.style.setProperty(
      "--color-secondary",
      darkThemeColors.get("secondary")
    );
    rootVariables.style.setProperty(
      "--color-text",
      darkThemeColors.get("text")
    );
    rootVariables.style.setProperty(
      "--color-background",
      darkThemeColors.get("background")
    );
  } else {
    // light theme

    rootVariables.style.setProperty(
      "--color-primary",
      lightThemeColors.get("primary")
    );
    rootVariables.style.setProperty(
      "--color-secondary",
      lightThemeColors.get("secondary")
    );
    rootVariables.style.setProperty(
      "--color-text",
      lightThemeColors.get("text")
    );
    rootVariables.style.setProperty(
      "--color-background",
      lightThemeColors.get("background")
    );
  }
}

Using this method we can actually maintain many themes in one site. I'm still learning javascript, so the above code looks crude. Will update it once I get better at it.

Update 20 March 2022

No need to add variables in css root, just call the function on load

window.onload = toggleDarkMode;

Also simplifying the code further. Instead of individual setProperties, use loops.

function toggleDarkMode() {
  let rootVariables = document.querySelector(":root");
  let darkMode = document.getElementById("toggle");

  if (darkMode.checked) {
    // dark theme

    for (let [key, value] of darkThemeColors.entries()) {
      rootVariables.style.setProperty("--color-" + key, value);
    }
  } else {
    // light theme

    for (let [key, value] of lightThemeColors.entries()) {
      rootVariables.style.setProperty("--color-" + key, value);
    }
  }
}

No bugs reported other than IDE errors and warnings for undeclared variables.

Disclaimer: This practice of declaring variables on the go for css is not recommended. Few browsers may have javascript disabled, which will result in the site looking like shit. Or some browsers may not support css variables. So please make sure you have fallback values set in place for better user experience.

Final javascript file

Peace.