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

codeTap to expand ⛶
1// Task Manager — CRUD with localStorage
2
3class TaskManager {
4 constructor(storageKey = "tasks") {
5 this.storageKey = storageKey;
6 this.tasks = this.load();
7 this.filter = "all"; // all, active, completed
8 this.sortBy = "date"; // date, priority, name
9 }
10
11 // CREATE
12 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 }
26
27 // READ
28 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);
34
35 return this.sortTasks(filtered);
36 }
37
38 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).length
43 };
44 }
45
46 // UPDATE
47 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 }
55
56 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 }
65
66 // DELETE
67 deleteTask(id) {
68 this.tasks = this.tasks.filter(t => t.id !== id);
69 this.save();
70 }
71
72 clearCompleted() {
73 this.tasks = this.tasks.filter(t => !t.completed);
74 this.save();
75 }
76
77 // Sorting
78 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 }
89
90 // Persistence
91 save() {
92 localStorage.setItem(this.storageKey, JSON.stringify(this.tasks));
93 }
94
95 load() {
96 try {
97 return JSON.parse(localStorage.getItem(this.storageKey)) || [];
98 } catch {
99 return [];
100 }
101 }
102}
103
104// Rendering
105function renderTasks(manager, container) {
106 const tasks = manager.getTasks();
107 const stats = manager.getStats();
108
109 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:

  1. Create the HTML with form for adding tasks, filters, and task list
  2. Style with CSS (animations for add/delete, strikethrough for complete)
  3. Implement all CRUD operations with localStorage
  4. Add filter buttons (All, Active, Completed)
  5. Add sort options (Date, Priority, Name)
  6. Implement drag-and-drop reordering
  7. 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.