Implement a Light and Dark Mode Toggle with JavaScript and Local Storage.
Building a Simple Light/Dark Mode Switcher with JavaScript and Local Storage
Introduction
If you want to learn how to toggle between light and dark modes on HTML, CSS, and JAVASCRIPT, then this practical tutorial is for you.
Live project: https://jstogglemode.netlify.app/
Source code: https://github.com/AlexDunia/Js-Toggle-Tech-Writing-source-code-
What is a Toggle in this context?
A toggle is a button or icon on a website or app that lets you switch between two options, like showing or hiding a menu, selecting filters, or changing between light and dark mode (Like in our case).
Setting up our Font Awesome Icons to toggle.
To set up this toggle, we need to get the icons for the buttons we want to use.
Here's how the toggle button looks on our website.
Clicking the icon circled red toggles between light and dark modes. We'll import two icons accordingly.
For this project, we will be using Font Awesome.
Sign up to open a new account or log in to continue with the old account.
Once this is done, we will visit our profile on 'Your Account'.
We want to make use of our kits, so we click on 'Your kits'.
and we click on the alphanumeric string on our profile:
We will then see the code we need to copy and paste for the icons we will use to toggle to be displayed.
Copy on our HTML
After this, we go back to the Font Awesome website to search for "Toggle".
We need two icons, toggle on and toggle off.
Copy and paste that into your HTML too.
Take note of the ID
here, we would be storing them in separate variables and using them as event listeners.
What is Local Storage?
Local Storage is a global object in the browser that lets websites store key/value pairs on a user's device.
What this means on a basic level is that a user can do something on a website, leave that website, restart their computer and that particular thing would remain the same when they get back to it. That's the power of the local storage.
In doing its work, it provides a set of methods (getItem, setItem, removeItem, clear, etc.) to interact with the stored data. You can find out more about local storage here.
In our use case, local storage will be useful in toggling dark and light mode and we begin by storing it inside a variable.
let mode = localStorage.getItem("mode");
We're creating a variable to hold our local storage value, ensuring we have a default when the page loads.
We are using let
so that its value can be reassigned later in the code.
This 'mode' variable will also help us track the current mode, making it easy to switch between light and dark modes.
If you knew how local storage works before this moment, then the question pops up: why are we using getItem, not setItem? aren't we supposed to initialize it first?
Yes. Either way is right, but in our use case, the trick here is that we are using let mode = localStorage.getItem("mode")
to retrieve the value of "mode" from local storage when the page loads.
Setting up our variables
For this project, we need four more variables, making the total 5.
Remember,mode
was a variable itself.
let toggleoff = document.querySelector("#toggleoff");
let toggleon = document.querySelector("#toggleon");
let herolarge = document.querySelector("#htx");
let herosub = document.querySelector("#htxtwo");
let mode = localStorage.getItem("mode");
toggleoff
and toggleon
represent the ID
for the font awesome class we just imported.
herolarge
selects the ID
hero's main text.
herosub
selects the ID
of the hero subheading.
Now when we need a function.
I assume you already have the basics of function covered, however, this is a link that properly explains functions in JavaScript.
Setting up our function.
Note: For now, we don't have an event listener to listen to the click, and this is intentional.
Moving forward, we will create a function called updateMode and pass in a parameter of "mode".
'Mode' is the same name we gave to the first variable we created.
Copy and paste this code into your editor. I will explain each line now.
function updateMode(mode) {
if (mode === 'darkmode') {
localStorage.setItem('mode', 'darkmode');
toggle.style.display = 'none';
toggleon.style.display = 'block';
herolarge.style.color = "white";
herosub.style.color = "white";
document.body.classList.add("darkmode");
document.body.classList.remove('lightmode');
} else {
localStorage.setItem('mode', 'lightmode');
toggle.style.display = 'block';
toggleon.style.display = 'none';
herolarge.style.color = "#000039";
herosub.style.color = "black";
document.body.classList.remove("darkmode");
document.body.classList.add('lightmode');
console.log('light mode');
}
}
Breaking down our Function.
First, we have a function with a parameter of mode.
This function is used to monitor and change the state of our toggle.
The 'mode' parameter corresponds to the name of our variable that gets the value of the local storage (the first variable we created) because we use the variable as an argument when calling the function.
What you need to understand here is that with the "mode" parameter, the function is aware of the current state stored in local storage.
Then, we have a condition:
if (mode === 'darkmode')
When we check if (mode === 'darkmode')
, it means we are verifying whether our variable (mode
), which is getting its value from local storage, is equal to 'darkmode'.
So what happens if it is equal to darkmode?
Remember, in the first instance we haven't explicitly set any local storage values yet, we used a getItem instead.
Now, Inside this condition, we'll be setting up our local storage for the first time:
localStorage.setItem('mode', 'darkmode');
This sets our value to "darkmode".
Our function has a condition that if our mode is darkmode, then we set a local storage called 'darkmode'.
After that, we move to these lines:
toggle.style.display = 'none';
toggleon.style.display = 'block';
These are the variables that control our Font Awesome icons.
When it is dark mode, our toggle button or toggle icon activates and needs to be 'on'.
Let's take a step back to properly understand.
Note: We are trying to control the dark mode here.
By default, our toggle is 'off.'
It is 'off' because our dark mode is off.
The toggle controls our dark mode.
When we click the button, the dark mode comes 'on', and so does our button.
This works vice versa because when the toggle is off, then our dark mode also goes off.
Turning on the night mode means showing the Font Awesome icon that displays the toggle "on."
In essence, the objective is to set the default state of the button as 'OFF.' When clicked, it toggles to 'ON,' activating the night mode and displaying the corresponding Font Awesome icon for the 'ON' state
If that is clear then we move to the next two lines:
document.body.classList.add("darkmode");
document.body.classList.remove('lightmode');
If we refer back to our CSS, specifically lines 38-44, we have two classes: one sets the background color to light mode (white), and the other sets it to dark mode (ash).
.lightmode{
background-color: white;
}
.darkmode{
background:#1b1b1b;
}
On our CSS, we also have the body:
body{
font-family:Montserrat;
overflow-x: hidden;
position: relative;
}
The body has no background color initially.
On the hero text and subtext, we have default colors(lines 49 and 54 specifically), this shows we can do it however we want to, provided there is a color.
#htx {
animation: fadeIn 1s ease-in-out 1.5s forwards;
line-height:1.1em;
color:#000039;
}
#htxtwo {
animation: fadeIn 1s ease-in-out 2.5s forwards;
color:black;
margin-top:15px;
font-weight:500;
}
The JavaScript code adds the appropriate background color and text color based on the selected mode.
The first half of our updateMode condition checks if the mode set in our local storage is darkmode.
If our stored mode is set to darkmode, we do the following:
Save dark mode in the storage,
Switch the icon from 'off' to 'on'.
Make the page dark.
Remove any light styles.
The terms 'dark mode' and 'light mode' here correspond to the CSS classes we have defined. The function updates the styles and adds them to the body of our website based on the selected mode.
Note: darkmode and lightmode are not prefixed names. You can name them anything you choose.
function updateMode(mode) {
if (mode === 'darkmode') {
localStorage.setItem('mode', 'darkmode');
toggleoff.style.display = 'none';
toggleon.style.display = 'block';
document.body.classList.add("darkmode");
herolarge.style.color = "white";
herosub.style.color = "white";
document.body.classList.remove('lightmode');
console.log('dark mode');
} else {
localStorage.setItem('mode', 'lightmode');
toggleoff.style.display = 'block';
toggleon.style.display = 'none';
herolarge.style.color = "#000039";
herosub.style.color = "black";
document.body.classList.remove("darkmode");
document.body.classList.add('lightmode');
console.log('light mode');
}
}
For the else condition, we reverse everything.
else{
localStorage.setItem('mode', 'lightmode');
toggleoff.style.display = 'block';
toggleon.style.display = 'none';
herolarge.style.color = "#000039";
herosub.style.color = "black";
document.body.classList.remove("darkmode");
document.body.classList.add('lightmode');
console.log('light mode');
}
If the mode is not darkmode, then we do the opposite: show the 'off' icon, hide the 'on' icon, switch the page to light mode, and remove any darkmode styles.
Now our function is ready to go, but it's not done yet.
We need two event listeners that listen for a click event outside the function.
This will be the toggle on and toggle off event.
Without these, our well-written function won't do anything.
That listener calls the function.
toggleon.addEventListener('click', function () {
updateMode('lightmode');
});
toggleoff.addEventListener('click', function () {
updateMode('darkmode');
});
When we click on the toggleon
, it triggers the updateMode
function with a parameter of lightmode
.
This implies that whenever we click on either the 'toggleon' or 'toggleoff' icon, we invoke the function to perform different actions.
and for the final piece of the puzzle:
if (mode === 'darkmode') {
updateMode('darkmode');
} else if (mode === 'lightmode'){
updateMode('lightmode');
} else {
updateMode('lightmode');
}
If the local storage mode is 'darkmode,' update to dark mode.
If the mode is 'lightmode,' update to light mode.
The additional condition is our DEFAULT STATE, and it handles situations where no mode is stored in local storage, which often occurs on page load. In such cases, the default action is to set the mode to 'lightmode,' ensuring the page loads in light mode by default.
This code helps maintain the user's preferred mode across page loads.
CONCLUSION
Adding beauty to the user interface (UI) via interaction is crucial because users find it visually appealing. Also, it is a good trick to learn as it gives beginners a friendly approach to logic in JavaScript and DOM manipulation.
Thanks for stopping by! If you found this helpful, consider giving it a like, dropping a comment, and hitting that follow button.