How to Build Your First Interactive To-Do List with Vanilla JavaScript
Read this article in clean Markdown format for LLMs and AI context.Ever opened a new tab and thought, “I need a simple place to jot down today’s tasks, but I don’t want to sign up for another app?” That moment is why a tiny to‑do list built with plain JavaScript is a perfect first project. It teaches you the basics of the DOM, events, and state without any heavy frameworks. Let’s get that list up and running, step by step.
What You’ll Need
Before we dive in, make sure you have:
- A text editor (VS Code, Sublime, or even Notepad will do)
- A modern web browser (Chrome, Firefox, Edge, etc.)
- A blank folder for the project
That’s it—no npm, no build tools, just the browser and a few files.
Setting Up the Files
Create three files in your project folder:
index.html– the page structurestyles.css– a little styling to make it look niceapp.js– the JavaScript that will make the list interactive
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My First To‑Do List</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<h1>My To‑Do List</h1>
<input type="text" id="new-task" placeholder="Add a new task...">
<button id="add-btn">Add</button>
<ul id="task-list"></ul>
</div>
<script src="app.js"></script>
</body>
</html>
A quick note: the <ul> element will hold each task as a list item (<li>). We give it an id so JavaScript can find it later.
styles.css
body {
font-family: Arial, sans-serif;
background: #f9f9f9;
margin: 0;
padding: 20px;
}
.container {
max-width: 400px;
margin: auto;
background: #fff;
padding: 20px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
input, button {
padding: 8px;
margin: 5px 0;
}
li {
display: flex;
justify-content: space-between;
padding: 5px 0;
}
.completed {
text-decoration: line-through;
color: #777;
}
Nothing fancy—just enough to keep the list readable. Feel free to tweak colors later.
Writing the JavaScript
Open app.js. We’ll break the code into small, understandable chunks.
Grab the Elements
const input = document.getElementById('new-task');
const addBtn = document.getElementById('add-btn');
const taskList = document.getElementById('task-list');
document.getElementById is a DOM method that finds an element by its id attribute. Think of the DOM as the page’s tree of elements; we’re just picking the branches we need.
Add a New Task
function addTask() {
const taskText = input.value.trim();
if (taskText === '') return; // ignore empty input
const li = document.createElement('li');
const span = document.createElement('span');
span.textContent = taskText;
const deleteBtn = document.createElement('button');
deleteBtn.textContent = '✖';
deleteBtn.className = 'delete';
li.appendChild(span);
li.appendChild(deleteBtn);
taskList.appendChild(li);
input.value = '';
}
trim()removes extra spaces at the start or end.createElementbuilds a new HTML element that we can later attach to the page.- We add a delete button (the little “✖”) so each item can be removed.
Hook Up the Add Button
addBtn.addEventListener('click', addTask);
addEventListener tells the browser, “When this button is clicked, run the addTask function.” This is the core of interactivity.
Make Tasks Clickable
We want two more interactions:
- Clicking the text toggles a “completed” style.
- Clicking the delete button removes the item.
taskList.addEventListener('click', function(e) {
const target = e.target;
// If the user clicked the delete button
if (target.classList.contains('delete')) {
const li = target.parentElement;
taskList.removeChild(li);
return;
}
// If the user clicked the task text
if (target.tagName === 'SPAN') {
target.classList.toggle('completed');
}
});
Why attach the listener to taskList instead of each <li>? Because the list may grow after the page loads. This technique, called event delegation, lets one listener handle many future items. It keeps the code simple and fast.
Optional: Add “Enter” Key Support
input.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
addTask();
}
});
Now you can type a task and press Enter—no need to click the button.
Test It Out
Open index.html in your browser. Try adding a few tasks, marking them as done, and deleting some. If everything works, congratulations! You just built a functional interactive app with only vanilla JavaScript.
What Did We Learn?
- DOM manipulation – creating elements, setting text, and appending them.
- Event handling – listening for clicks and key presses.
- State management – the list itself is the state; we update it directly.
- Event delegation – a single listener can manage many dynamic items.
These are the building blocks for any web app. Once you’re comfortable here, you can start adding features like local storage (so the list persists after a page reload) or drag‑and‑drop reordering.
A Little Personal Note
When I first started coding, I built a to‑do list that only let me add items. I spent a whole afternoon debugging why the delete button didn’t work—turns out I forgot to stop the click event from bubbling up. That little hiccup taught me the value of reading the console and stepping through code line by line. If you hit a snag, open the browser’s developer tools (F12) and watch the console. It’s like a friendly detective that tells you exactly where things went wrong.
Next Steps
- Persist data – use
localStorage.setItemandlocalStorage.getItemto save the list. - Add edit mode – let users double‑click a task to change its text.
- Style it up – experiment with CSS variables or a light/dark theme toggle.
The sky’s the limit, but the best way to learn is by building. Keep tweaking, keep testing, and soon you’ll be comfortable adding more complex logic to your projects.
Happy coding from JS Beginner Hub!
- → Mastering Asynchronous JavaScript: Real‑World Patterns for Faster Front‑End Performance @codecraftchronicles
- → How to Build a CSS‑Only Responsive Accordion (No JavaScript Needed) @csstricksreference
- → The Ultimate JavaScript Debugging Cheat Sheet: 25 Shortcuts Every Developer Needs @codecheatsheet
- → Build a Real‑World Image Classifier with PyTorch: A Step‑by‑Step Tutorial @mltutorialhub
- → Designing a Multi-Stud Terminal Board: Step-by-Step Guide for Embedded Projects @studterminals