JavaScript
Tutorial: build a complete to-do list
Combine arrays, events, and localStorage to build a real to-do list that remembers your data.
This is the project where everything so far (arrays, functions, events, localStorage) comes together. If you followed the previous tutorials to get here, this will feel surprisingly familiar.
Step 1: the HTML
<form id="task-form">
<input type="text" id="new-task" placeholder="New task" />
<button type="submit">Add</button>
</form>
<ul id="task-list"></ul>
Step 2: your app's state (just an array)
let tasks = JSON.parse(localStorage.getItem('tasks')) || [];
When the page loads, we try to recover saved tasks. If there's nothing saved yet (first visit), we fall back to an empty array thanks to the || operator.
Step 3: render the tasks on screen
function renderTasks() {
const list = document.querySelector('#task-list');
list.innerHTML = '';
tasks.forEach((task, index) => {
const item = document.createElement('li');
item.textContent = task;
const deleteButton = document.createElement('button');
deleteButton.textContent = 'Delete';
deleteButton.addEventListener('click', () => deleteTask(index));
item.appendChild(deleteButton);
list.appendChild(item);
});
}
Step 4: add and remove tasks, and save everything
function saveTasks() {
localStorage.setItem('tasks', JSON.stringify(tasks));
}
function deleteTask(index) {
tasks = tasks.filter((_, i) => i !== index);
saveTasks();
renderTasks();
}
document.querySelector('#task-form').addEventListener('submit', (event) => {
event.preventDefault();
const input = document.querySelector('#new-task');
const text = input.value.trim();
if (text === '') return;
tasks.push(text);
input.value = '';
saveTasks();
renderTasks();
});
renderTasks();
Every time you add or remove a task: you update the array, save it to localStorage, and re-render the whole list. It's a pattern you'll repeat your entire career as a developer, so memorize it well (or just bookmark this tutorial, no shame in that).
What did you just learn?
- How to combine arrays, DOM events, and
localStoragein a real project. - The "update data → save → re-render" pattern you'll use constantly.
- That you can already build something functional with what you know, no frameworks yet.