Building a To-Do App with JavaScript: A Step-by-Step Project for Beginners

Building a To-Do App with JavaScript: A Step-by-Step Project

You’ve learned how to manipulate the DOM, handle events, and render dynamic lists. Now let’s apply those skills to building a To-Do App which is fully functional using plain JavaScript.

This project will teach you:

  • How to structure your HTML and CSS
  • How to manage tasks with arrays and objects
  • How to add, delete, and persist tasks
  • How to use localStorage for saving data
  • How to handle events efficiently with delegation

Step 1: HTML Structure

<div class="todo-app">
  <h1>My To-Do List</h1>
  <input type="text" id="taskInput" placeholder="Enter a task" />
  <button id="addTaskBtn">Add Task</button>
  <ul id="taskList"></ul>
</div>

Step 2: Basic CSS Styling

.todo-app {
  max-width: 400px;
  margin: auto;
  padding: 20px;
  background: #f9f9f9;
  border-radius: 8px;
}

input {
  width: 70%;
  padding: 10px;
  margin-right: 10px;
}

button {
  padding: 10px;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
}

ul {
  list-style: none;
  padding: 0;
}

li {
  background: #e0e0e0;
  margin-top: 10px;
  padding: 10px;
  display: flex;
  justify-content: space-between;
}

Step 3: JavaScript Logic

✅ Initial Setup

const taskInput = document.getElementById("taskInput");
const addTaskBtn = document.getElementById("addTaskBtn");
const taskList = document.getElementById("taskList");

let tasks = JSON.parse(localStorage.getItem("tasks")) || [];

➕ Add Task

function addTask() {
  const text = taskInput.value.trim();
  if (text === "") return;

  const task = { id: Date.now(), text };
  tasks.push(task);
  saveTasks();
  renderTasks();
  taskInput.value = "";
}

addTaskBtn.addEventListener("click", addTask);

🗑️ Delete Task (Event Delegation)

taskList.addEventListener("click", event => {
  if (event.target.classList.contains("delete-btn")) {
    const id = Number(event.target.dataset.id);
    tasks = tasks.filter(task => task.id !== id);
    saveTasks();
    renderTasks();
  }
});

🖼️ Render Tasks

function renderTasks() {
  taskList.innerHTML = "";
  tasks.forEach(task => {
    const li = document.createElement("li");
    li.innerHTML = `
      ${task.text}
      <button class="delete-btn" data-id="${task.id}">Delete</button>
    `;
    taskList.appendChild(li);
  });
}

💾 Save to localStorage

function saveTasks() {
  localStorage.setItem("tasks", JSON.stringify(tasks));
}

Try It Yourself

Add these features:

  • ✅ Mark tasks as completed
  • 📝 Edit tasks inline
  • 🔍 Filter tasks (All, Completed, Pending)
  • 📅 Add due dates and sort by deadline

Bonus: Add animations and theme switching!


Performance Tips

  • Use event delegation for delete/edit buttons
  • Avoid re-rendering the entire list unless necessary
  • Use DocumentFragment for batch DOM updates if needed

Final Thoughts

This project ties together everything you’ve learned; DOM manipulation, event handling, dynamic rendering, and client-side storage. It’s a perfect beginner project that can evolve into a full productivity app.

In the next post, we’ll explore JavaScript Modules and Code Organization — how to split your code into reusable, maintainable pieces.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top