Project 3: Task Manager with LocalStorage
📖 Concept
Build a full CRUD (Create, Read, Update, Delete) task manager that persists data using localStorage. This project practices state management, CRUD operations, localStorage, DOM manipulation, and event handling.
Features:
- Add, edit, and delete tasks
- Mark tasks as complete/incomplete
- Filter by status (all, active, completed)
- Sort by date, priority, or name
- Drag and drop to reorder
- Data persistence with localStorage
- Categories/tags for organization
Concepts practiced: CRUD, localStorage, DOM events, Event delegation, Array methods, Destructuring, Template literals
💻 Code Example
1// Task Manager — CRUD with localStorage23class TaskManager {4 constructor(storageKey = "tasks") {5 this.storageKey = storageKey;6 this.tasks = this.load();7 this.filter = "all"; // all, active, completed8 this.sortBy = "date"; // date, priority, name9 }1011 // CREATE12 addTask(title, { priority = "medium", category = "general" } = {}) {13 const task = {14 id: crypto.randomUUID(),15 title,16 completed: false,17 priority,18 category,19 createdAt: new Date().toISOString(),20 updatedAt: new Date().toISOString()21 };22 this.tasks.unshift(task);23 this.save();24 return task;25 }2627 // READ28 getTasks() {29 let filtered = this.tasks;30 if (this.filter === "active")31 filtered = filtered.filter(t => !t.completed);32 if (this.filter === "completed")33 filtered = filtered.filter(t => t.completed);3435 return this.sortTasks(filtered);36 }3738 getStats() {39 return {40 total: this.tasks.length,41 active: this.tasks.filter(t => !t.completed).length,42 completed: this.tasks.filter(t => t.completed).length43 };44 }4546 // UPDATE47 toggleTask(id) {48 const task = this.tasks.find(t => t.id === id);49 if (task) {50 task.completed = !task.completed;51 task.updatedAt = new Date().toISOString();52 this.save();53 }54 }5556 editTask(id, updates) {57 const task = this.tasks.find(t => t.id === id);58 if (task) {59 Object.assign(task, updates, {60 updatedAt: new Date().toISOString()61 });62 this.save();63 }64 }6566 // DELETE67 deleteTask(id) {68 this.tasks = this.tasks.filter(t => t.id !== id);69 this.save();70 }7172 clearCompleted() {73 this.tasks = this.tasks.filter(t => !t.completed);74 this.save();75 }7677 // Sorting78 sortTasks(tasks) {79 const sorters = {80 date: (a, b) => new Date(b.createdAt) - new Date(a.createdAt),81 priority: (a, b) => {82 const order = { high: 0, medium: 1, low: 2 };83 return order[a.priority] - order[b.priority];84 },85 name: (a, b) => a.title.localeCompare(b.title)86 };87 return [...tasks].sort(sorters[this.sortBy] || sorters.date);88 }8990 // Persistence91 save() {92 localStorage.setItem(this.storageKey, JSON.stringify(this.tasks));93 }9495 load() {96 try {97 return JSON.parse(localStorage.getItem(this.storageKey)) || [];98 } catch {99 return [];100 }101 }102}103104// Rendering105function renderTasks(manager, container) {106 const tasks = manager.getTasks();107 const stats = manager.getStats();108109 container.innerHTML = `110 <div class="stats">111 <span>${stats.total} total</span>112 <span>${stats.active} active</span>113 <span>${stats.completed} done</span>114 </div>115 <ul class="task-list">116 ${tasks.map(task => `117 <li class="task ${task.completed ? 'completed' : ''}"118 data-id="${task.id}" draggable="true">119 <input type="checkbox" ${task.completed ? 'checked' : ''}>120 <span class="title">${task.title}</span>121 <span class="priority priority-${task.priority}">122 ${task.priority}123 </span>124 <button class="delete-btn">×</button>125 </li>126 `).join("")}127 </ul>128 `;129}
🏋️ Practice Exercise
Build It Yourself:
- Create the HTML with form for adding tasks, filters, and task list
- Style with CSS (animations for add/delete, strikethrough for complete)
- Implement all CRUD operations with localStorage
- Add filter buttons (All, Active, Completed)
- Add sort options (Date, Priority, Name)
- Implement drag-and-drop reordering
- Bonus: Add categories, due dates, and search functionality
⚠️ Common Mistakes
Not validating input — empty titles, missing fields
Mutating the task array directly instead of using methods — breaks reactivity
Not debouncing localStorage writes — saving on every keystroke is expensive
Forgetting to re-render after state changes
Not handling the case when localStorage is full (5MB limit)
💼 Interview Questions
🎤 Mock Interview
Mock interview is powered by AI for Project 3: Task Manager with LocalStorage. Login to unlock this feature.