javascriptsvgsetattribute

Changing between themes with Javascript


I'm trying to make a dark/light theme toggle on my website. The SVG file switches back and forth on every click, but there's an issue with the theme not switching every click.

First two clicks - theme changes as expected.

Third and fourth clicks - SVG image still changes each click, but theme doesn't change

Fifth and sixth clicks onward - theme changes as expected, cycle repeats

HTML:

<div id="themes">
   <img id="current-theme">
</div>

CSS:

body{
  background-color: #ccc;
}

#themes {
  text-align: right;
  margin-right: 10em;
  margin-top: 2em;
  transform: scale(1.5);
  cursor: pointer;
}

.dark-mode {
  background-color: rgb(65, 65, 65);
  transition: background-color 0.5s ease;

  h1 {
    color: white;
  }

  h3 {
    color: white;
  }

  button {
    background-color: white;
    color: black;
  }
}

.light-mode {
  background-color: #ccc;
  transition: background-color 0.5s ease;

  h1 {
    color: var(--primary-color);
  }

  h3 {
    color: black;
  }

  button {
    background-color: black;
    color: white;
  }
}

Javascript:

//default theme is light
document.getElementById("current-theme").src = "images/moon.svg"

var currentTheme = document.getElementById("current-theme");
currentTheme.setAttribute("onClick", "toDarkTheme()");

var theme = document.body;

function toDarkTheme() {

  document.getElementById("current-theme").src = "images/sun.svg";
  theme.classList.toggle("dark-mode");
  //currentTheme.removeAttribute("onClick");
  currentTheme.setAttribute("onClick", "toLightTheme()");
}

function toLightTheme() {

  document.getElementById("current-theme").src = "images/moon.svg";
  theme.classList.toggle("light-mode");
  //currentTheme.removeAttribute("onClick");
  currentTheme.setAttribute("onClick", "toDarkTheme()");
}


I've included a link to the code in jsfiddle so you can see exactly what's happening. Thank you for any help/advice you can give!

https://jsfiddle.net/6op0fx7L/2/#&togetherjs=zTrev7ILNd


Solution

  • At the beginning theme.classList is empty

    Then with each subsequent click, you get the following state changes...

    1. theme.classList becomes dark-mode
    2. theme.classList becomes dark-mode, light-mode
    3. theme.classList becomes light-mode
    4. theme.classList becomes empty

    I.e. dark-mode adds or cancels dark-mode, it doesn't do anything to light-mode and vice-versa.

    You could give both functions both toggles provided you toggle light-mode explicitly at the beginning. Like this...

    //default theme is light
    document.getElementById("current-theme").src = "images/moon.svg"
    
    var currentTheme = document.getElementById("current-theme");
    currentTheme.setAttribute("onClick", "toDarkTheme()");
    
    var theme = document.body;
    theme.classList.toggle("light-mode");
    
    function toDarkTheme() {
    
      document.getElementById("current-theme").src = "images/sun.svg";
      theme.classList.toggle("dark-mode");
        theme.classList.toggle("light-mode");
    
      //currentTheme.removeAttribute("onClick");
      currentTheme.setAttribute("onClick", "toLightTheme()");
    }
    
    function toLightTheme() {
    
      document.getElementById("current-theme").src = "images/moon.svg";
      theme.classList.toggle("light-mode");
        theme.classList.toggle("dark-mode");
    
      //currentTheme.removeAttribute("onClick");
      currentTheme.setAttribute("onClick", "toDarkTheme()");
    }
    body{
      background-color: #ccc;
    }
    
    #themes {
      text-align: right;
      margin-right: 10em;
      margin-top: 2em;
      transform: scale(1.5);
      cursor: pointer;
    }
    
    .dark-mode {
      background-color: rgb(65, 65, 65);
      transition: background-color 0.5s ease;
    
      h1 {
        color: white;
      }
    
      h3 {
        color: white;
      }
    
      button {
        background-color: white;
        color: black;
      }
    }
    
    .light-mode {
      background-color: #ccc;
      transition: background-color 0.5s ease;
    
      h1 {
        color: var(--primary-color);
      }
    
      h3 {
        color: black;
      }
    
      button {
        background-color: black;
        color: white;
      }
    }
    <div id="themes">
      <!--The icon and theme will change on click-->
      <img id="current-theme">
    </div>