Step-by-Step Guide to Creating a ToDo App with Complete CRUD Functionality


Code of this ToDo App (look the about section to try this)
Introduction:
A ToDo app is one of the most classic beginner projects for front‑end web development. This will give you a hands on of HTML , CSS and JavaScript with fundamental concept of CRUD (Create, Read, Update, Delete) operations. In my writing , you’ll see how to build a fully functional ToDo application from scratch, complete with persistent storage using the browser’s Local Storage API.
By the end of this guide, you’ll be able to:
Structure your HTML for user input and task display
Apply modern CSS for a clean and responsive UI
Implement JavaScript to handle user interactions
Perform CRUD operations on tasks
Save, retrieve, and update tasks in Local Storage
I hope this blog will be helpful.
Prerequisites:
Before you begin, make sure you have:
Basic knowledge of HTML, CSS, and JavaScript
A modern web browser ( Chrome in my case)
A code editor (VS Code [ I used this ], Cursor etc.)
Project Setup:
Create a new folder:
todo-app
Inside it, create three files:
index.html
styles.css
script.js
Open the folder in your code editor.
Creating the HTML Structure:
Open index.html
and add the following boilerplate:
codes are copy & pasted from my project so please check the comments and everything before running…
<!DOCTYPE html><html lang="en">
<head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>TO DO LIST</title> <link rel="stylesheet" href="style.css"></head>
<body> <main> <div class="box"> <h1 id="title">YOU HAVE TO DO THESE WITHIN TODAY (<span id="current-date"></span>)</h1> <div class="input-container"> <input type="text" id="item" autofocus placeholder="Write something here..."> <button id="add-new-task">ADD task</button> </div> <ul id="to-do-box"> </ul> <div class="footer"> <p>Made by <a href="https://soumyodeep-dey.vercel.app/" target="_blank">Soumyodeep Dey</a></p> </div> </div> </main> <script src="https://kit.fontawesome.com/bf520e6492.js" crossorigin="anonymous"></script> <script> // Add current date to the title const currentDate = new Date().toLocaleDateString(); document.getElementById('current-date').textContent = currentDate; </script> <script src="app.js"></script></body>
</html>
your HTML should look like this (format the above code I leave that to you)
Styling with CSS:
Open styles.css
and include a clean, responsive design:
codes are copy & pasted from my project so please check the comments and everything before running…
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300&display=swap');
* { padding: 0; margin: 0; box-sizing: border-box; font-family: 'Open Sans', sans-serif;}
main { width: 100%; height: 100vh; display: flex; justify-content: center; align-items: center; background-color: #ecf0f1; background-image: url('https://images.unsplash.com/photo-1506748686214-e9df14d4d9d0?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzNjUyOXwwfDF8c2VhcmNofDJ8fHRvZG98ZW58MHx8fHwxNjg5NTY1NzA3&ixlib=rb-4.0.3&q=80&w=1080');}
.box { width: 700px; min-height: 500px; background-color: white; border-radius: 5px; padding: 15px;}
.input-container { display: flex; align-items: center; gap: 10px;}
#add-new-task { padding: 10px 20px; font-size: 16px; font-weight: bold; background-color: #2980b9; color: white; border: none; border-radius: 5px; cursor: pointer; box-shadow: 0px 0px 2px grey;}
#add-new-task:hover { background-color: #1c598a;}
#item { flex: 1; padding: 10px; font-size: 20px; border: 0; outline: 0; font-weight: bold; box-shadow: 0px 0px 2px grey;}
#to-do-box { margin-top: 20px; list-style: none;}
#to-do-box li { display: flex; justify-content: space-between; align-items: center; padding: 10px; background-color: #f8f9fa; /* Light background for better contrast */ color: #343a40; /* Darker text color */ border: 1px solid #dee2e6; /* Add a subtle border */ border-radius: 5px; margin-top: 10px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* Add a subtle shadow */ transition: transform 0.2s ease; /* Add hover effect */}
#to-do-box li:hover { transform: scale(1.02); /* Slightly enlarge on hover */ background-color: #e9ecef; /* Slightly darker background on hover */}
#to-do-box li i { position: absolute; right: 10px; top: 10px;}
/* Style for completed tasks */.done { text-decoration: line-through; /* Strike-through text */ color: gray; /* Dim the text color */ background-color: #e0e0e0; /* Light gray background for completed tasks */ font-style: italic; /* Optional: make the text italic for emphasis */ transition: background-color 0.3s ease, color 0.3s ease; /* Smooth transition for visual changes */}
#title { text-align: center; font-size: 35px; margin-bottom: 20px; font-weight: 800; color: red;}
/* Style for the button container */.button-container { display: inline-flex; /* Align buttons horizontally */ align-items: center; /* Center align buttons vertically */ gap: 5px; /* Add spacing between buttons */ font-size: 14px; /* Adjust font size for better readability */}
/* Style for the edit button */.edit-btn { background-color: #007bff; /* Blue background */ border: none; color: white; /* White text */ font-size: 14px; padding: 5px 10px; /* Add padding for button-like appearance */ border-radius: 5px; /* Rounded corners */ cursor: pointer; transition: background-color 0.3s ease, transform 0.2s ease; /* Smooth hover effect */}
.edit-btn:hover { background-color: #0056b3; /* Darker blue on hover */ transform: scale(1.05); /* Slightly enlarge on hover */}
.edit-btn.disabled { opacity: 0.5; pointer-events: none;}
/* Style for the delete button */.delete-btn { background-color: #dc3545; /* Red background */ border: none; color: white; /* White text */ font-size: 14px; padding: 5px 10px; /* Add padding for button-like appearance */ border-radius: 5px; /* Rounded corners */ cursor: pointer; transition: background-color 0.3s ease, transform 0.2s ease; /* Smooth hover effect */}
.delete-btn:hover { background-color: #a71d2a; /* Darker red on hover */ transform: scale(1.05); /* Slightly enlarge on hover */}
/* Style for the separator */.button-separator { margin: 0 5px; /* Add spacing around the separator */ color: #6c757d; /* Neutral gray color */ font-size: 14px; font-weight: bold; /* Make the separator more prominent */}
.footer { text-align: center; padding: 15px 10px; background: rgba(0, 0, 0, 0.6); /* Semi-transparent for readability */ color: #ccc; font-size: 14px; position: relative; /* change to fixed or sticky if you want it always visible */ margin-top: 40px; border-top: 1px solid rgba(255, 255, 255, 0.1); backdrop-filter: blur(5px); /* Optional: glass effect */}
.footer a { color: #00c4ff; text-decoration: none; font-weight: bold; transition: color 0.3s ease;}
.footer a:hover { color: #fff; text-decoration: underline;}
Adding JavaScript Logic :
Open script.js
. We'll organize the code into sections for clarity.
codes are copy & pasted from my project so please check the comments and everything before running…
Initializing Data:
const item = document.getElementById("item");
const toDoBox = document.getElementById("to-do-box");
const ADD = document.getElementById("add-new-task");
let todos = JSON.parse(localStorage.getItem('tasks')) || [];
Create Operation (Add Todo):
// Function to add a new task
function addTask() {
const TaskText = item.value.trim();
if (TaskText === "") return; // Prevent empty tasks
const NewTask = {
id: Date.now(),
text: TaskText,
completed: false
};
todos.push(NewTask);
save(); // Save tasks to localStorage
item.value = ""; // Clear input field
display(NewTask); // Display the new task
}
// Add task on button click
ADD.addEventListener('click', addTask);
// Add task on Enter key press
item.addEventListener('keydown', (e) => {
if (e.key === "Enter") {
addTask();
}
});
- Save Tasks to local storage:
// Save tasks to localStorage
function save() {
localStorage.setItem('tasks', JSON.stringify(todos));
}
- Display a task with it you will find edit and delete functionality :
// Display a task
const display = (todo) => {
const li = document.createElement("li");
li.style.display = "flex";
li.style.alignItems = "center";
li.style.justifyContent = "space-between";
const textSpan = document.createElement("span");
textSpan.textContent = todo.text;
li.appendChild(textSpan);
// Create a container for buttons
const buttonContainer = document.createElement("div");
buttonContainer.classList.add("button-container");
// Add delete functionality
const deleteBtn = document.createElement("button");
deleteBtn.innerHTML = "Delete";
deleteBtn.classList.add("delete-btn");
deleteBtn.addEventListener("click", (e) => {
e.stopPropagation();
todos = todos.filter((t) => t.id !== todo.id);
save();
li.remove();
});
// Add "edit" functionality
const editBtn = document.createElement("button");
editBtn.innerHTML = "Edit";
editBtn.classList.add("edit-btn");
editBtn.addEventListener("click", (e) => {
e.stopPropagation();
if (todo.completed) return;
// Create input field and replace the span
const input = document.createElement("input");
input.type = "text";
input.value = todo.text;
input.style.flex = "1";
li.replaceChild(input, textSpan);
input.focus();
// Save changes on blur or Enter key
const saveEdit = () => {
const newText = input.value.trim();
if (newText) {
todo.text = newText;
textSpan.textContent = newText;
save();
}
li.replaceChild(textSpan, input); // Restore the span
};
input.addEventListener("blur", saveEdit);
input.addEventListener("keydown", (e) => {
if (e.key === "Enter") {
saveEdit();
}
});
});
// Add a separator between buttons
const separator = document.createElement("span");
separator.textContent = "|";
separator.classList.add("button-separator");
// Append buttons and separator to the container
buttonContainer.appendChild(editBtn);
buttonContainer.appendChild(separator);
buttonContainer.appendChild(deleteBtn);
li.appendChild(buttonContainer);
// Apply "done" class if task is completed
if (todo.completed) {
li.classList.add('done');
}
// Add toggle functionality for marking a task as completed
li.addEventListener("click", () => {
todo.completed = !todo.completed; // Toggle the completed status
li.classList.toggle("done"); // Toggle the "done" class
// Disable edit button if completed, enable if not
if (todo.completed) {
editBtn.disabled = true;
editBtn.classList.add("disabled");
} else {
editBtn.disabled = false;
editBtn.classList.remove("disabled"); }
save(); // Save the updated tasks to localStorage
});
toDoBox.appendChild(li);
};
- And don’t forget to add DOM Content loader :
document.addEventListener('DOMContentLoaded', () => {
// full js code
}
Deploying:
Create a Github repo for this
Use github pages for deploy
It will be free and easy “_”
Conclusion:
Congratulations! You've built a complete ToDo application with all CRUD operations and Local data storage. Now use these learning for building another projects and don’t forget to tag me :)
Subscribe to my newsletter
Read articles from SOUMYODEEP DEY directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

SOUMYODEEP DEY
SOUMYODEEP DEY
I'm Soumyodeep Dey currently pursuing my B.Tech in CS. Throughout my journey, I have gained some experience in various programming languages and other tools that have allowed me to undertake personal projects and two internships so far. I strive to apply my knowledge to real-world scenarios and to make meaningful contributions to the industry. If you are reading this please connect, collaborate, or discuss. You can contact me at soumyodeepdey2003@gmail.com or connect with me on my socials. And THANK YOU for visiting my profile , means a lot to me.