Project: A To-Do App

Time to put it all together. In this final lesson you'll build a complete to-do app: adding, completing, editing and deleting tasks, filtering them, and saving everything so it survives a reload. It uses variables, functions, arrays, objects, DOM manipulation, events, delegation and storage — most of this course in about 80 lines.

The finished app

Try it first: add a few tasks, tick some off, double-click a task to edit it, switch filters, then press Reset on the editor — your tasks are still there.

Try it yourself
Result

How it's structured

The app follows a pattern used by almost every front-end framework:

  1. State — a single array, todos, plus the current filter. This is the source of truth.
  2. Render — one function rebuilds the list from the state. It never reads data back out of the page.
  3. Actions — event handlers change the state, then call render().

Because the page is always drawn from the state, it can't drift out of sync. React, Vue and Svelte automate exactly this loop — understanding it here makes those frameworks much easier to learn.

Key techniques used

TechniqueWhereLesson
Objects in an array as statetodos29, 36
map, filter, findRendering and updates31
Spread to update immutably{ ...t, done: !t.done }33
Creating elements, replaceChildrenrender()43
textContent for user text (XSS-safe)Task text43
Form submit + preventDefaultAdding tasks44, 46
Event delegation with closest and data-*List and filter clicks45
localStorage + JSON with try/catchload(), save()41, 48, 54
crypto.randomUUID() for IDsNew tasks50

Challenges

Extend the app in the editor above. Each challenge practises a different part of the course:

  1. Due dates — add a date input to the form, store due on each task, and show overdue tasks in red (lesson 20).
  2. Sort — add a button that sorts tasks alphabetically with localeCompare (lesson 32).
  3. Inline editing — replace the prompt with an input that appears in place of the text, saving on Enter and cancelling on Escape (lesson 44).
  4. Keyboard shortcut — focus the new-task field when the user presses / (lesson 44).
  5. Modules — move the app into your own project, split into storage.js, render.js and main.js (lesson 55).
  6. Sync — load initial tasks from https://jsonplaceholder.typicode.com/todos?_limit=5 with fetch when storage is empty (lesson 49).

What next?