Home > Net >  Use Single button to toggle two functions for easy Light and Dark Mode
Use Single button to toggle two functions for easy Light and Dark Mode

Time:04-14

I have a code that allows me to easily switch from light mode to dark mode without having to write css for dark mode, it works with two buttons, each executing either the light mode or dark mode depending on your choice of click. However i want to merge this two functions into one single button so that it can be used to toggle the function. If anyone answering does include how it can be used with a toggle button, that won't be bad at all... The code i am using is

const htmlEl = document.getElementsByTagName('html')[0];

const toggleTheme = (theme) => {
    htmlEl.dataset.theme = theme;
}
html {
    transition: color 300ms, background-color 300ms !important;
}

html[data-theme='dark'] {
    background: #000;
    filter: invert(1) hue-rotate(180deg)
}

html[data-theme='dark'] img {
  filter: invert(1) hue-rotate(180deg)
}
<button onclick="toggleTheme('dark');">Dark Mode Test</button>
    
<button onclick="toggleTheme('light');">Light Mode Test</button>

<br><font color="red">WE ARE RED</font>
<br><font color="blue">WE ARE BLUE</font>
<br><font color="black">WE ARE Black</font>

Then i tried to execute the switch using Eventlisteners this way

<script>
   var btn = document.getElementById('navbtn');

btn.addEventListener('click', function() {
  var foo = 'dark';
 
    if (foo === "light") {
        toggleTheme('dark');
    } else {
        toggleTheme('light');
    }

}, false);
</script>

This however only reacts on first click and not on second. What could be the best way to achieve this? Thanks in anticipation.

CodePudding user response:

Here ya go, with some flare from a switch I made awhile back anyway. If you want verification just open your dev tools and watch the data attribute of the example HTML change live.

const htmlEl = document.documentElement,
      outputExample = document.getElementById('output');
      
let savedTheme = 'light';

// ********************************************************************
//  NOTE: The localStorage example WILL NOT WORK HERE ON STACKOVERFLOW
//        Instead it will throw a "SecurityError" and rightfully so...
//        You'll have to use that part of the example in your
//        own project to see it in action...... JUST FYI.
//        So you will need to UNCOMMENT the commented out stuff for
//        the localstorage example to work. Left it commented out for
//        for other readers to not see the valid securityerror....
// ********************************************************************

// Toggle the theme and update their local storage.
toggleTheme = (bool) => {
   const theme = bool ? 'light' : 'dark';
   htmlEl.dataset.theme = theme;
   // localStorage.setItem('savedTheme', theme);
   
   outputExample.innerText = `${theme} theme`;
}

// Handle their saved preferred theme.
setSavedTheme = () => {

  // If there is no current theme in localstorage then give them one as a default.
  // Like for first time visitors...
  // Uncomment this block and the localstorage piece above for the localstorage example.
  /*
  if (localStorage.getItem('savedTheme') === null) {
    localStorage.setItem('savedTheme', savedTheme);
  } else {
    savedTheme = localStorage.getItem('savedTheme');
  }
  */
  
  htmlEl.dataset.theme = savedTheme;
  outputExample.innerText = `${savedTheme} theme`;
}

// Set the default.
setSavedTheme();
.slide-toggle {
  position: relative;
  font-weight: 600;
  display: inline-block;
  border-radius: 3px;
}
.slide-toggle input:first-of-type {
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0;
}
.slide-toggle input:first-of-type:focus ~ label {
  box-shadow: 0 0 0 6px rgba(255, 0, 0, 0.15);
}
.slide-toggle input:first-of-type:checked ~ label {
  color: #fff;
  background-color: darkorange;
}
.slide-toggle input:first-of-type:checked ~ label:after {
  transform: translateX(100%);
}
.slide-toggle input:first-of-type:disabled ~ label {
  opacity: 0.5;
  pointer-events: none;
}
.slide-toggle label:first-of-type {
  display: flex;
  height: 2rem;
  width: 4rem;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  user-select: none;
  outline: none;
  color: #777;
  background-color: #ddd;
  border-radius: 3px;
  transition: background-color 0.25s ease, box-shadow 0.15s ease, color 0.25s ease;
}
.slide-toggle label:first-of-type:hover {
  border-color: #777;
  box-shadow: 0 0 0 6px rgba(225, 0, 0, 0.15);
}
.slide-toggle label:first-of-type:after {
  content: "";
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 3px;
  right: 50%;
  border-radius: 3px;
  background-color: #fff;
  transition: transform 0.25s cubic-bezier(0.6, 0.82, 0, 0.76);
}
.slide-toggle label:first-of-type:hover {
  box-shadow: 0 0 0 6px rgba(225, 0, 0, 0.15);
}
.slide-toggle label:first-of-type div {
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: center;
}

html {
  transition: background-color .3s ease;
}

html[data-theme="light"] {
  background-color: #fff;
}

html[data-theme="dark"] {
  color: #fff;
  background-color: #212121;
}

body {
  height: 50vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css">

<div >
  <input id="guidLater"
         type="checkbox" checked
         onchange="toggleTheme(this.checked)"/>
  <label for="guidLater">
    <div><i ></i></div>
    <div><i ></i></div>
  </label>
</div>

<div id="output" style="margin-top: 1rem"></div>

CodePudding user response:

btn.addEventListener('click', function() {
  var foo = 'dark';
 
    if (foo === "light") {
        toggleTheme('dark');
    } else {
        toggleTheme('light');
    }

}, false);

Is wrong.

You need to grab the current theme from the clicked on element (you have it set in data-theme attribute of the element).

Your code just sets the theme as "dark" every time a button is clicked, rather than actually accepting the current value, and toggling it.


btn.addEventListener('click', function(event) {
  var currentTheme= event.currentTarget.dataset.theme;
 
    if (currentTheme=== "light") {
        toggleTheme('dark');
    } else {
        toggleTheme('light');
    }

}, false);

Also, remove your inline calls of toggleTheme, and only call the function from the handler on the click event listener.

<button data-theme="dark">Dark Mode Test</button>
    
<button data-theme="light">Light Mode Test</button>

  • Related