DEV Community

Cover image for To-Do List in Vanilla JavaScript
Vijay Kumar
Vijay Kumar

Posted on

To-Do List in Vanilla JavaScript

🧠 Build a Jaw-Dropping To-Do List in Vanilla JavaScript.

Let’s get something straight: there are a million to-do list tutorials out there. Most are bloated, half-baked, or full of libraries that you barely need.

But real developers?
They solve problems with the bare minimum. They build function-first, readable code. That’s what we’re doing today — building a fully functional To-Do List in Vanilla JS from zero to awesome.


💥 The Problem

We want a tool that:

  • Adds tasks
  • Deletes tasks
  • Marks tasks as done
  • Stores tasks between page reloads (localStorage)

But we’re not here to copy-paste junk. We’re going to understand and own every line.


🧱 The Structure (HTML)

Here's the minimal layout — no fluff.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Vanilla JS To-Do</title> <style> body { font-family: sans-serif; background: #111; color: #eee; display: flex; flex-direction: column; align-items: center; margin-top: 50px; } input, button { padding: 10px; margin: 5px; border-radius: 5px; border: none; } ul { list-style: none; padding: 0; max-width: 300px; width: 100%; } li { background: #222; margin: 5px 0; padding: 10px; display: flex; justify-content: space-between; align-items: center; border-radius: 5px; } li.done { text-decoration: line-through; opacity: 0.6; } .remove-btn { background: crimson; color: white; cursor: pointer; } </style> </head> <body> <h1>🧠 Just Do It</h1> <input type="text" id="taskInput" placeholder="Enter task" /> <button id="addBtn">Add Task</button> <ul id="taskList"></ul> <script src="app.js"></script> </body> </html> 
Enter fullscreen mode Exit fullscreen mode

🧠 The Logic (JavaScript)

Now we enter the core battle ground: app.js

const taskInput = document.getElementById('taskInput'); const addBtn = document.getElementById('addBtn'); const taskList = document.getElementById('taskList'); let tasks = JSON.parse(localStorage.getItem('tasks')) || []; // 🛠 Render tasks from array function renderTasks() { taskList.innerHTML = ''; // Clear previous tasks.forEach((task, index) => { const li = document.createElement('li'); li.className = task.done ? 'done' : ''; li.innerHTML = ` <span>${task.text}</span> <div> <button onclick="toggleDone(${index})">✔</button> <button class="remove-btn" onclick="deleteTask(${index})">✖</button> </div> `; taskList.appendChild(li); }); localStorage.setItem('tasks', JSON.stringify(tasks)); } // ➕ Add task addBtn.addEventListener('click', () => { const text = taskInput.value.trim(); if (text === '') return alert('Enter something useful!'); tasks.push({ text, done: false }); taskInput.value = ''; renderTasks(); }); // ✅ Toggle task status function toggleDone(index) { tasks[index].done = !tasks[index].done; renderTasks(); } // ❌ Delete task function deleteTask(index) { tasks.splice(index, 1); renderTasks(); } // 🔁 On load renderTasks(); 
Enter fullscreen mode Exit fullscreen mode

🧠 Problem Solved — Let’s Break It Down

  1. Persistent Data:
    We use localStorage — your tasks stay alive even after closing the tab.

  2. No Frameworks:
    Just JavaScript. Because when you learn this, frameworks become tools, not crutches.

  3. Event-Driven:
    Clicks trigger behavior. Code responds. Simple & reactive.

  4. Clean UX:

  • to toggle done
  • to delete
  • Tasks saved automatically

⚡ Bonus Power: Keyboard Add

Want to make it snappy? Add this:

taskInput.addEventListener('keypress', e => { if (e.key === 'Enter') addBtn.click(); }); 
Enter fullscreen mode Exit fullscreen mode

Now you can hit Enter to add a task — like a real productivity machine.


🚀 Final Words

You didn’t just make a to-do list.
You wrote a real app with zero dependencies, a clean mental model, and real-world utility.

This is how a problem-solver thinks: less fluff, more flow.

Top comments (6)

Collapse
 
kooiinc profile image
KooiInc • Edited

Ah yes, the Todo app. Here's one I concocted (vanilla JS, uses event delegation for handling stuff)

Collapse
 
vjygour profile image
Vijay Kumar • Edited

Looks good! Clean and simple I like how you handled the logic—simple but effective.

Collapse
 
nevodavid profile image
Nevo David

pretty cool honestly, sometimes i forget how much you can get done with just pure js - you ever feel like using frameworks kinda makes you skip learning the basics?

Collapse
 
vjygour profile image
Vijay Kumar

Yes I skip a lot earlier, but right now i came back to fundamentals , Frameworks also makes developer life easy in so many like we don't need to write all the boiler plate code and so many other things but foundation is necessary too , so i'm trying to keep the balance now.

Collapse
 
dotallio profile image
Dotallio

Love how you kept it truly minimal and readable, especially the localStorage part.
Have you ever tried adding basic drag-and-drop for reordering tasks as a next step?

Collapse
 
vjygour profile image
Vijay Kumar

Thanks! Glad you liked the localStorage part—it took some tweaking to keep it clean.
Drag-and-drop is definitely on my list, might try a lightweight approach next!