Back to Blog
Lesson 30 of the JavaScript: From Zero to Interactive Web Pages course
JavaScriptAugust 17, 20264 min read

Removing To-Do Items: Mastering Event Delegation in JavaScript

Learn how to remove to-do items using event delegation. Discover how to identify clicked elements and update your DOM dynamically in this practical guide.

JavaScriptDOMEvent DelegationFrontend DevelopmentTo-Do List
Close-up of colorful JavaScript code displayed on a computer monitor, ideal for tech-themed projects.

Previously in this course, we explored handling form submissions and rendering our to-do list. Now that you can add and display tasks, the next logical step is to allow users to remove them.

In this lesson, we will implement the "delete" functionality. While you might be tempted to attach a unique event listener to every single "delete" button, that approach is inefficient and messy. Instead, we will use event delegation to manage removals cleanly.

Why Event Delegation?

When you add new to-do items dynamically to your page, those items don't exist when the browser first loads. If you try to attach an event listener to a button that hasn't been created yet, your code will fail.

Event delegation solves this by leveraging "event bubbling." When a user clicks a button, that event doesn't just trigger the button's own listener; it "bubbles up" through the parent elements (the list container, the body, etc.). By attaching one listener to a stable parent element, we can catch clicks on any of its children—even those added later.

Implementing the Delete Functionality

Top view of red stationery items and planner arranged on a pink surface.

To delete a task, we need to:

  1. Listen for clicks on the list container.
  2. Identify if the clicked element is the "delete" button.
  3. Find the specific to-do item (the <li>) associated with that button.
  4. Remove that <li> from the DOM.

Worked Example: The Delete Logic

Let's assume your HTML structure includes a <ul> with an ID of todo-list. When we generate our list items, we include a button with a specific class like delete-btn.

JAVASCRIPT
// 1. Select the container
const todoList = document.querySelector(CE9178">'#todo-list');

// 2. Attach a single listener to the parent container
todoList.addEventListener(CE9178">'click', (event) => {
    // 3. Check if the clicked element has the CE9178">'delete-btn' class
    if (event.target.classList.contains(CE9178">'delete-btn')) {
        
        // 4. Find the closest parent <li> and remove it
        const itemToRemove = event.target.closest(CE9178">'li');
        itemToRemove.remove();
        
        console.log(CE9178">'Task removed successfully.');
    }
});

Breaking Down the Code

  • event.target: This refers to the specific element that was clicked.
  • classList.contains('delete-btn'): This is a guard clause. We only want to run our removal logic if the user actually clicked the delete button, not just the text next to it.
  • .closest('li'): This is a powerful DOM method. It traverses up the DOM tree from the button until it finds the first <li> element. This ensures that no matter how complex your button's internal HTML might be (e.g., an icon inside a button), you always target the correct container to remove.

Hands-on Exercise

Update your to-do dashboard project by performing these steps:

  1. Modify your existing function that creates new list items to include a <button class="delete-btn">Delete</button> inside each <li>.
  2. Add the event delegation logic shown above to your main JavaScript file.
  3. Test it by adding three tasks and removing the middle one. Ensure the others remain untouched.

Common Pitfalls

  • Forgetting event.target: If you try to remove an item without checking the target, any click inside your list container (even on the text itself) might trigger a deletion. Always filter by class or tag.
  • Incorrect Selector: Beginners often use parentNode multiple times (e.g., event.target.parentNode.parentNode). This is brittle; if you change your HTML structure, your code breaks. Using .closest('li') is much more resilient.
  • Listener Overload: Avoid adding an addEventListener inside a loop for every new item. While it works for small lists, it consumes more memory and makes event management significantly harder as your application grows.

Frequently Asked Questions

What if I have icons inside my delete button? event.target will return the icon (like an <i> or <span>). Because you are using .closest('li'), the logic remains perfectly intact, as it correctly identifies the parent <li> regardless of what inner element was clicked.

Is event delegation faster? Yes. You only attach one event listener to the browser memory instead of one per list item. It is a standard pattern in modern web development, also popularized in frameworks like React, which uses a similar concept to handle events efficiently.

Recap

We successfully implemented a delete feature by moving from individual event listeners to a centralized listener on the parent container. By using event.target and .closest('li'), we've created a robust way to manage dynamic content that is easy to maintain.

Up next: Now that we can remove tasks, let's learn how to interact with them by toggling their completion status.

Similar Posts