Capstone Project: Todo App
Congratulations on reaching the final lesson! Over the past 27 lessons you've learned about variables, functions, arrays, the DOM, events, JSON, async programming, classes, and more. Now it's time to tie it all together and build a complete small application. This project will be the culmination of everything you've learned.
Project Overview
We'll build a Todo App — it may look simple, but it touches nearly every core concept you've studied. When you're done, you'll have a real, usable productivity tool.
Feature Requirements
- Add todo items — input field + button; pressing Enter or clicking adds a new item
- Toggle complete/incomplete — click a todo to toggle its done state (strikethrough effect)
- Delete todo items — each item has a delete button beside it
- Filtering — three buttons: All / Active / Completed
- Local storage — use
localStorageto persist data across page refreshes - Count remaining items — display "X items left" at the bottom
Technical Requirements
| Concept | Where It's Used |
|---|---|
| Class | TodoApp class organizes all logic |
| async/await | Wrap localStorage read/write as async functions |
| DOM manipulation | Dynamically create list items, update content, remove elements |
| Event handling | Form submit, list click, filter button click |
| JSON | JSON.stringify to save, JSON.parse to load |
| Array methods | filter, map, find to manage todo data |
| Template literals | Build HTML strings |
Acceptance Criteria
- [ ] All 6 features work correctly
- [ ] Data persists after page refresh
- [ ] Code has clear comments
- [ ] No
alert/prompt/confirm— use in-page interactions instead - [ ] Empty input is rejected (with a message)
Reference Implementation Ideas
Below are hints and directions — not complete code. Writing it yourself is where the real learning happens.
Data Structure
<script>
// Each todo item is an object
const todo = {
id: Date.now(), // unique identifier
text: 'Learn JavaScript',
completed: false
};
console.log(todo);
// All todo items are stored in an array
let todos = [];
</script>
Class Structure
<script>
class TodoApp {
constructor() {
this.todos = []; // data
this.filter = 'all'; // current filter
this.init(); // initialize
}
async init() {
// 1. Load data from localStorage
// 2. Bind events
// 3. Render the list
}
async save() {
// JSON.stringify → localStorage.setItem
}
async load() {
// localStorage.getItem → JSON.parse
}
addTodo(text) { /* create object, push, save, render */ }
toggleTodo(id) { /* find the item, flip completed, save, render */ }
deleteTodo(id) { /* filter out the item, save, render */ }
render() {
// 1. Filter todos based on this.filter
// 2. Clear the list container
// 3. Loop through filtered array, create DOM nodes
// 4. Update the count display
}
}
</script>
Event Binding Strategy
- Form
submit:e.preventDefault()→ get input value →addTodo(text)→ clear input - List
click(event delegation): check ife.targetis the toggle or delete button → call the appropriate method - Filter button
click: updatethis.filter→render()
Rendering Strategy
<script>
render() {
const filtered = this.todos.filter(function(todo) {
if (this.filter === 'active') return !todo.completed;
if (this.filter === 'completed') return todo.completed;
return true; // 'all'
}.bind(this));
// Clear the container
this.listEl.innerHTML = '';
filtered.forEach(function(todo) {
var li = document.createElement('li');
// Set content, styles, data attributes
// Bind toggle and delete events
this.listEl.appendChild(li);
}.bind(this));
// Update the count
var activeCount = this.todos.filter(function(t) { return !t.completed; }).length;
this.countEl.textContent = activeCount + ' items left';
}
</script>
Extension Ideas
Once the basic features are working, try these advanced challenges:
- 🔄 Drag & drop sorting — implement with the HTML5 Drag & Drop API or touch events
- ✏️ Editing — double-click a todo to enter edit mode, press Enter to save
- 🏷️ Category tags — add labels (work / study / life) and filter by tag
- 🎨 Theme switching — dark/light theme, persisted with
localStorage - ⏰ Due date reminders — add a deadline to each item, highlight overdue ones in red
Assignment
Complete the todo app above with all features, and pass all acceptance criteria.
Suggested steps:
- Start with the HTML structure and CSS styling
- Build the
TodoAppclass skeleton (constructor,init) - Implement
addTodoandrender— get adding to work first - Implement
toggleTodo— toggle complete/incomplete - Implement
deleteTodo— remove items - Implement filtering
- Implement
saveandload— persist data - Show the remaining item count
- Final polish: empty input validation, style tweaks
📝 Exercises
- Basic: Complete the core todo features — add, toggle complete, delete — using an array for storage (no
localStorageneeded). - Intermediate: Add
localStoragepersistence and filtering (All / Active / Completed) to the basic version; data should survive a page refresh. - Challenge: Implement at least one extension feature (drag & drop sorting, editing, category tags, theme switching, or due date reminders), and write a brief explanation of your approach.



