Skip to Content
Course content

180: Building an Interactive To-Do List

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Think of building a to-do list like managing a physical whiteboard with a stack of sticky notes. When you decide you have a new task, you don't redraw the entire whiteboard from scratch. You grab a fresh sticky note, write the task on it, and slap it onto the board. If you finish the task, you might put a checkmark on it. If the task becomes irrelevant, you rip the note off and throw it in the trash. Your board stays the same, but the content on it is constantly evolving.

In JavaScript, we do exactly the same thing with the DOM. Here is how that maps to our code:

  • The Whiteboard: This is your container element (like a <ul>) that already exists in your HTML.
  • The Sticky Note: This is a new element created via document.createElement('li').
  • Writing the Note: This is when you take the value from your input field and assign it to the textContent of your new element.
  • Slapping it on the Board: This is the appendChild() method.
  • Ripping it off: This is the remove() method triggered by a delete button.

Turning an input field into a living list item

I've noticed a lot of people try to use innerHTML += '...' to add items to a list. Please, don't do that. It wipes out all existing event listeners on your list every time you add a new item because it re-renders the entire block of HTML. Instead, we build the element as a JavaScript object first, then attach it to the DOM.

const taskInput = document.querySelector('#task-input');
const taskList = document.querySelector('#task-list');
const addBtn = document.querySelector('#add-btn');

addBtn.addEventListener('click', () => {
    const taskText = taskInput.value;
    if (taskText === "") return; // Don't add empty notes to our board!

    // Create the "sticky note"
    const li = document.createElement('li');
    li.textContent = taskText;

    // Create the "rip it off" button
    const deleteBtn = document.createElement('button');
    deleteBtn.textContent = 'X';
    deleteBtn.onclick = () => li.remove();

    // Assemble and place on the board
    li.appendChild(deleteBtn);
    taskList.appendChild(li);

    taskInput.value = ""; // Clear the input for the next task
});

Handling the "Checkmark" state

To handle completion, we don't want to change the text; we want to change the style. The cleanest way to do this is by toggling a CSS class. This keeps your logic in the JS and your visuals in the CSS, which is how you'll be doing it in professional environments.

I like to add a click event to the li itself. When the user clicks the text, we toggle a .completed class that might add a text-decoration: line-through.

li.addEventListener('click', (e) => {
    // We check if the user clicked the delete button specifically
    // so we don't mark the task as complete while trying to delete it.
    if (e.target !== deleteBtn) {
        li.classList.toggle('completed');
    }
});

By nesting the delete button's logic and the list item's toggle logic inside the same creation function, each "sticky note" carries its own behavior with it. You aren't managing a giant list of indices; you're managing individual, self-contained objects.




📋 Practical Task

Implementing a Task Priority Color-Coder

Now it's your turn to extend the functionality. Your goal is to modify the to-do list so that users can specify a priority level before adding the task.

Requirements:

  • Add a <select> dropdown to your HTML with three options: "Low", "Medium", and "High".
  • When a task is added, the <li> should receive a specific CSS class based on the selected priority (e.g., .priority-low, .priority-medium, .priority-high).
  • In your CSS, assign a different border-left color to each priority class (e.g., Green for Low, Orange for Medium, Red for High).
  • Ensure that clicking the task to "complete" it still works regardless of the priority color.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.