I need to switch from ‘Light mode’ to ‘Dark mode’ and vice versa in one single Button and I’m having some issues with my if/else statement, clik event and ‘hasAttribute’ method. I don’t know why this doesn’t work.
How my program works:
I have an attribute insid my HTML tag called ‘data-theme’ to switch from light to dark and dark to light:
<html lang="en" data-theme="light">
Then, in y SCSS file I define my colors for each theme:
html { //Colors here for Light }
html[data-theme="dark"] { //Colors here for Dark }
Finally in my JavaScript file I have this code:
const mainButton = document.querySelector('.primary-cta');
// ~~~ Dark~Light Mode ~~~
mainButton.addEventListener('click', function (event) {
event.preventDefault();
if (document.documentElement.hasAttribute('data-theme', 'light')) {
// Light to Dark
document.documentElement.setAttribute('data-theme', 'dark');
} else if (document.documentElement.hasAttribute('data-theme', 'dark')) {
// Dark to Light
document.documentElement.setAttribute('data-theme', 'light');
}
})
It works switching from Light to Dark but if I try, later, to change to Light just doesn’t work. I can’t see where I’m falling . Full project / CODEPEN: https://codepen.io/ricardorien/pen/OJbxYYa
Be mindful of what exactly is happening when you use .hasAttribute('data-theme', 'light').
If you go over the API here: Element.hasAttribute() - Web APIs | MDN hasAttribute(name) only accepts one parameter and it returns a boolean based on the first attribute data-theme. Since you’re coding in JS, the javascript compiler won’t care beyond the first single param you passed in; the params after the first one are ignored. On the surface it looks like you’re checking if data-theme='light' exists, but in fact it’s just checking to see if data-theme exists. The first time you run, it changes to dark because it does exist so the first if block runs. But once you click again, data-theme still exists (dark) so it will setAttribute('data-theme', 'dark') and no visible change is made (except for setting data-theme to dark again).
So what you want to do is use another method such as element.getAttribute(name) to get the value of data-theme to check whether it’s in light or dark mode. Element.hasAttribute() - Web APIs | MDN
This is a common problem with coding in Javascript and on Codepen; it won’t raise any errors since it’s loosely type based. You can make a bunch of unknown method calls and it won’t raise any errors until runtime. I recommend coding in Typescript so it will yell at you if you try to pass incorrect number of params for a function.
What a grat explenation! So, that’s what happened. Thanks for that method, and for taking your time to solve this problem. Finally I can understand what is happen thanks to you, Final Code:
mainButton.addEventListener('click', function (event) {
event.preventDefault();
if (document.documentElement.getAttribute('data-theme') === 'light') {
// Light to Dark
document.documentElement.setAttribute('data-theme', 'dark');
} else {
// Dark to Light
document.documentElement.setAttribute('data-theme', 'light');
}
})