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

SOUMYODEEP DEYSOUMYODEEP DEY
10 min read

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:

  1. Create a new folder: todo-app

  2. Inside it, create three files:

    • index.html

    • styles.css

    • script.js

  3. 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…

  1. 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')) || [];
  1. 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();        
    }    
    });
  1. Save Tasks to local storage:
 // Save tasks to localStorage    
    function save() {        
    localStorage.setItem('tasks', JSON.stringify(todos));    
    }
  1. 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);    
};
  1. And don’t forget to add DOM Content loader :
document.addEventListener('DOMContentLoaded', () => {
  // full js code
}

Deploying:

  1. Create a Github repo for this

  2. Use github pages for deploy

  3. 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 :)

20
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.