Building an Advanced To-Do List with Drag & Drop and Local Storage
A to-do list is one of the most common beginner projects in web development, but in this blog post, we'll take it to the next level! 🚀 We’ll build an advanced to-do list using HTML, CSS, and JavaScript, featuring:
✅ Drag & Drop functionality ✅ Local Storage support (Tasks persist even after refreshing) ✅ Dynamic Task Management
This guide will walk you through the code and explain how everything works step by step.
🔹 Features of This To-Do List
🛠️ Full Code for the Advanced To-Do List
Here’s the complete code for your interactive to-do list:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Advanced To-Do List</title>
<style>
body { font-family: Arial, sans-serif; margin: 30px; }
#todoList { list-style: none; padding: 0; }
#todoList li { padding: 10px; margin: 5px; background: #f0f0f0; border: 1px solid #ccc; cursor: grab; }
.dragging { opacity: 0.5; }
</style>
</head>
<body>
<h1>Advanced To-Do List</h1>
<input type="text" id="newTask" placeholder="New Task">
<button id="addTask">Add Task</button>
<ul id="todoList"></ul>
<script>
const todoList = document.getElementById('todoList');
const newTaskInput = document.getElementById('newTask');
const addTaskButton = document.getElementById('addTask');
// Retrieve saved tasks or initialize an empty array.
let tasks = JSON.parse(localStorage.getItem('tasks')) || [];
// Render the tasks on the page.
function renderTasks() {
todoList.innerHTML = '';
tasks.forEach((task, index) => {
const li = document.createElement('li');
li.textContent = task;
li.draggable = true;
li.dataset.index = index;
li.addEventListener('dragstart', dragStart);
li.addEventListener('dragover', dragOver);
li.addEventListener('drop', drop);
todoList.appendChild(li);
});
localStorage.setItem('tasks', JSON.stringify(tasks));
}
// Add a new task.
function addTask() {
const task = newTaskInput.value.trim();
if (task) {
tasks.push(task);
newTaskInput.value = '';
renderTasks();
}
}
addTaskButton.addEventListener('click', addTask);
// Drag & drop functions.
let draggedIndex;
function dragStart(e) {
draggedIndex = e.target.dataset.index;
e.target.classList.add('dragging');
}
function dragOver(e) {
e.preventDefault(); // Necessary to allow dropping.
}
function drop(e) {
e.preventDefault();
const targetIndex = e.target.dataset.index;
if (draggedIndex !== targetIndex) {
// Swap tasks.
[tasks[draggedIndex], tasks[targetIndex]] = [tasks[targetIndex], tasks[draggedIndex]];
renderTasks();
}
}
renderTasks();
</script>
</body>
</html>
📌 Breaking Down the Code
1️⃣ HTML Structure
The HTML is simple:
<input type="text" id="newTask" placeholder="New Task">
<button id="addTask">Add Task</button>
<ul id="todoList"></ul>
2️⃣ Styling with CSS
The CSS styles make the to-do list visually appealing:
#todoList li {
padding: 10px;
margin: 5px;
background: #f0f0f0;
border: 1px solid #ccc;
cursor: grab;
}
.dragging {
opacity: 0.5;
}
3️⃣ Storing Tasks in Local Storage
To save tasks even after a page refresh, we use the localStorage API. Tasks are stored as an array of strings:
// Retrieve saved tasks or initialize an empty array.
let tasks = JSON.parse(localStorage.getItem('tasks')) || [];
Every time the tasks are updated, they are saved back into localStorage:
Recommended by LinkedIn
localStorage.setItem('tasks', JSON.stringify(tasks));
4️⃣ Adding New Tasks
When the user enters a task and clicks "Add Task":
function addTask() {
const task = newTaskInput.value.trim();
if (task) {
tasks.push(task);
newTaskInput.value = '';
renderTasks();
}
}
addTaskButton.addEventListener('click', addTask);
5️⃣ Implementing Drag & Drop
We use the HTML5 Drag & Drop API to enable reordering tasks.
Dragging a Task
function dragStart(e) {
draggedIndex = e.target.dataset.index;
e.target.classList.add('dragging');
}
Dragging Over Another Task
To allow dropping, we prevent the default behavior.
function dragOver(e) {
e.preventDefault();
}
Dropping a Task in a New Position
function drop(e) {
e.preventDefault();
const targetIndex = e.target.dataset.index;
if (draggedIndex !== targetIndex) {
[tasks[draggedIndex], tasks[targetIndex]] = [tasks[targetIndex], tasks[draggedIndex]];
renderTasks();
}
}
🎯 Final Thoughts
This advanced to-do list project showcases: ✅ Local Storage for persistence ✅ Drag & Drop for interactive reordering ✅ Vanilla JavaScript with no external dependencies
🔥 Suggested Enhancements
Want to improve it further? Try adding: