Hey everyone. Welcome to this tutorial. In this tutorial, we will learn how to create a to-do list app with local storage. To build this app we need HTML, CSS and Javascript.
This is an intermediate-level javascript project. If you are looking for more projects to improve your javascript skills you can check out this playlist here. This playlist consists of 100+ javascript projects.
The difficulty level of these projects varies from simple to quite complex ones. Hence these projects are suitable for everyone including javascript beginners to javascript intermediates.
Video Tutorial:
If you are interested to learn by watching a video tutorial rather than reading this blog post you can check out the video down below. Also do not forget to subscribe to my youtube channel where I post new tips, tricks and tutorials every alternate day.
Along with these, I post multiple choice questions based on HTML, CSS and Javascript that will help you with your interviews.
Project Folder Structure:
Before we begin coding we take a look at the project folder structure. We create a project folder called – ‘To Do List With Local Storage’. Within this folder, we have three files. These files are index.html, style.css and script.js. The first file is the HTML document, the next one is the stylesheet and lastly, we have the script file.
HTML:
We begin with the HTML code. First, copy the code below and paste it into your HTML document.
<!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>To Do List With Local Storage</title> <!-- Font Awesome Icons --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css" /> <!-- Google Fonts --> <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap" rel="stylesheet" /> <!-- Stylesheet --> <link rel="stylesheet" href="style.css" /> </head> <body> <div class="container"> <div id="new-task"> <input type="text" placeholder="Enter The Task Here..." /> <button id="push">Add</button> </div> <div id="tasks"></div> </div> <!-- Script --> <script src="script.js"></script> </body> </html>
CSS:
Next, we style this app using CSS. Now copy provided to you below and paste it into your stylesheet.
* { padding: 0; margin: 0; box-sizing: border-box; } body { background-color: #0b87ff; } .container { width: 90%; max-width: 34em; position: absolute; transform: translate(-50%, -50%); top: 50%; left: 50%; } #new-task { position: relative; background-color: #ffffff; padding: 1.8em 1.25em; border-radius: 0.3em; box-shadow: 0 1.25em 1.8em rgba(1, 24, 48, 0.15); display: grid; grid-template-columns: 9fr 3fr; gap: 1em; } #new-task input { font-family: "Poppins", sans-serif; font-size: 1em; border: none; border-bottom: 2px solid #d1d3d4; padding: 0.8em 0.5em; color: #111111; font-weight: 500; } #new-task input:focus { outline: none; border-color: #0b87ff; } #new-task button { font-family: "Poppins", sans-serif; font-weight: 500; font-size: 1em; background-color: #0b87ff; color: #ffffff; outline: none; border: none; border-radius: 0.3em; cursor: pointer; } #tasks { background-color: #ffffff; position: relative; padding: 1.8em 1.25em; margin-top: 3.8em; width: 100%; box-shadow: 0 1.25em 1.8em rgba(1, 24, 48, 0.15); border-radius: 0.6em; } .task { background-color: #ffffff; padding: 0.3em 0.6em; margin-top: 0.6em; display: flex; align-items: center; border-bottom: 2px solid #d1d3d4; cursor: pointer; } .task span { font-family: "Poppins", sans-serif; font-size: 0.9em; font-weight: 400; } .task button { color: #ffffff; padding: 0.8em 0; width: 2.8em; border-radius: 0.3em; border: none; outline: none; cursor: pointer; } .delete { background-color: #fb3b3b; } .edit { background-color: #0b87ff; margin-left: auto; margin-right: 3em; } .completed { text-decoration: line-through; }
Javascript:
Finally, we implement the functionality of this app using javascript. We do this in eight simple steps:
- Create Initial References
- Implement Function On Window Load
- Function To Display Tasks
- Set Function To Disable Edit Tasks
- Function To Remove Tasks From Local Storage
- A Function To Add Tasks To Local Storage
- Function To Add A New Task
- Add Functionality To Edit & Delete Buttons
//Initial References const newTaskInput = document.querySelector("#new-task input"); const tasksDiv = document.querySelector("#tasks"); let deleteTasks, editTasks, tasks; let updateNote = ""; let count; //Function on window load window.onload = () => { updateNote = ""; count = Object.keys(localStorage).length; displayTasks(); }; //Function to Display The Tasks const displayTasks = () => { if (Object.keys(localStorage).length > 0) { tasksDiv.style.display = "inline-block"; } else { tasksDiv.style.display = "none"; } //Clear the tasks tasksDiv.innerHTML = ""; //Fetch All The Keys in local storage let tasks = Object.keys(localStorage); tasks = tasks.sort(); for (let key of tasks) { let classValue = ""; //Get all values let value = localStorage.getItem(key); let taskInnerDiv = document.createElement("div"); taskInnerDiv.classList.add("task"); taskInnerDiv.setAttribute("id", key); taskInnerDiv.innerHTML = `<span id="taskname">${key.split("_")[1]}</span>`; //localstorage would store boolean as string so we parse it to boolean back let editButton = document.createElement("button"); editButton.classList.add("edit"); editButton.innerHTML = `<i class="fa-solid fa-pen-to-square"></i>`; if (!JSON.parse(value)) { editButton.style.visibility = "visible"; } else { editButton.style.visibility = "hidden"; taskInnerDiv.classList.add("completed"); } taskInnerDiv.appendChild(editButton); taskInnerDiv.innerHTML += `<button class="delete"><i class="fa-solid fa-trash"></i></button>`; tasksDiv.appendChild(taskInnerDiv); } //tasks completed tasks = document.querySelectorAll(".task"); tasks.forEach((element, index) => { element.onclick = () => { //local storage update if (element.classList.contains("completed")) { updateStorage(element.id.split("_")[0], element.innerText, false); } else { updateStorage(element.id.split("_")[0], element.innerText, true); } }; }); //Edit Tasks editTasks = document.getElementsByClassName("edit"); Array.from(editTasks).forEach((element, index) => { element.addEventListener("click", (e) => { //Stop propogation to outer elements (if removed when we click delete eventually rhw click will move to parent) e.stopPropagation(); //disable other edit buttons when one task is being edited disableButtons(true); //update input value and remove div let parent = element.parentElement; newTaskInput.value = parent.querySelector("#taskname").innerText; //set updateNote to the task that is being edited updateNote = parent.id; //remove task parent.remove(); }); }); //Delete Tasks deleteTasks = document.getElementsByClassName("delete"); Array.from(deleteTasks).forEach((element, index) => { element.addEventListener("click", (e) => { e.stopPropagation(); //Delete from local storage and remove div let parent = element.parentElement; removeTask(parent.id); parent.remove(); count -= 1; }); }); }; //Disable Edit Button const disableButtons = (bool) => { let editButtons = document.getElementsByClassName("edit"); Array.from(editButtons).forEach((element) => { element.disabled = bool; }); }; //Remove Task from local storage const removeTask = (taskValue) => { localStorage.removeItem(taskValue); displayTasks(); }; //Add tasks to local storage const updateStorage = (index, taskValue, completed) => { localStorage.setItem(`${index}_${taskValue}`, completed); displayTasks(); }; //Function To Add New Task document.querySelector("#push").addEventListener("click", () => { //Enable the edit button disableButtons(false); if (newTaskInput.value.length == 0) { alert("Please Enter A Task"); } else { //Store locally and display from local storage if (updateNote == "") { //new task updateStorage(count, newTaskInput.value, false); } else { //update task let existingCount = updateNote.split("_")[0]; removeTask(updateNote); updateStorage(existingCount, newTaskInput.value, false); updateNote = ""; } count += 1; newTaskInput.value = ""; } });
That’s all for this tutorial. If you face any issues while creating this code you can download the source code by clicking on the ‘Download Code’ button below. Also if you have any queries, suggestions or feedback you can comment below.
Happy Coding!
I’m very excited with the content, but the code, when downloaded is only the CSS someone can access.