Skip to content
WANCODE
BM

To-do App That Remembers

1.5 hBeginnerJavaScriptDOMEventsArrayslocalStorage

Outcome

A to-do list where you can add tasks, tick them off, delete them, filter All / Active / Completed, see how many are left — and find everything still there after reloading the page.

Learning objectives

  • Keep app state in one array and redraw the DOM from it with a render() function
  • Create elements with document.createElement and attach event listeners to them
  • Use filter, find and push to update and query an array of objects
  • Persist data with localStorage, JSON.stringify and JSON.parse

Prerequisites

  • JavaScript basics: variables, functions, arrays, objects and addEventListener — see the JavaScript track
  • Comfortable reading simple HTML forms (the Tip & Bill Splitter project is good practice)

Expected behaviour

  • Typing a task and pressing Enter (or Add) adds it to the list and clears the input. Blank tasks are ignored.
  • Ticking a task's checkbox crosses it out; unticking restores it. The Delete button removes it.
  • All / Active / Completed show the matching tasks, and “N items left” is always correct.
  • After a refresh, every task (and whether it's done) is still there.

Almost every app you'll ever build follows the same loop: something happens → update the state → redraw the screen. A to-do list is the smallest app that shows this loop clearly, which is why every developer builds one.

JavaScript
let todos = [
  { id: "a1", text: "Beli susu", done: false },
  { id: "b2", text: "Siapkan assignment", done: true },
];

// event → change the array → render() redraws everything from it

The array is the truth. The list on screen is just a picture of it.

You'll use filter (delete, filter views) and find (toggle) a lot in this project.

The preview emulates localStorage per project, and it's kept between check runs — so items you add while testing may still be there next time. That's the feature working!

Milestones

Make the form work:

1. Listen for the form's submit event and call event.preventDefault(). 2. Read input.value.trim(). If it's empty, stop. 3. Push an object like { id, text, done: false } into todos. 4. Clear the input and call render().

Then write render(): empty the list (list.innerHTML = "") and create one <li> per to-do with the text inside a <span>. Use textContent for the text — never innerHTML for user input.

Checks

  • Submitting adds an <li> with the text
  • The to-do is stored in the todos array
  • The input is cleared after adding
  • Blank input is ignored
Completion checklist

Tick these when they're true for your project. The project completes when every milestone passes and every item is ticked.

Preview

Console output from your code appears here.

Step 1 of 5