Build an Interactive Task Tracker
Build a task tracker web app using vanilla JavaScript and DOM manipulation.
Introduction
30 Second Summary
Everyone has a mental list of things they need to get done. Whether it's groceries, homework, or work tasks, keeping track of it all in your head gets overwhelming fast.
In this project, you will build a task tracker web app using JavaScript. You'll create an interactive page where you can add tasks, mark them as complete with a strikethrough, and delete them.
What You'll Build
A browser-based task tracker built with HTML, CSS, and vanilla JavaScript that lets you manage a dynamic to-do list.
By the end of this project, you'll have:
- An index.html file with the page structure for your task tracker.
- A style.css file with visual styling that centers and polishes your app.
- A script.js file with interactive logic for adding, completing, and deleting tasks.
- Secret Mission: Add a live task counter and save your tasks with localStorage so they survive a page refresh.
Are there any prerequisites?
None. This guide walks you through installing everything from scratch, including VS Code and a browser. No prior coding experience is required.
Install and Set Up VS Code
Every web project needs a code editor to write and organize your files. Visual Studio Code (VS Code) is a free, popular editor used by professional developers worldwide.
In this step, you'll install VS Code, create a project folder on your desktop, and set up the three files that make up your task tracker app.
In this step, get ready to:
- Install Visual Studio Code on your computer.
- Create a task-tracker project folder on your desktop.
- Set up index.html, style.css, and script.js files.
Download and install Visual Studio Code
VS Code is the code editor you'll use to write your HTML, CSS, and JavaScript. It's free and works on both macOS and Windows.
- Visit the VS Code download page at https://code.visualstudio.com.
✔️ I already have VS Code installed
You're all set. Skip ahead to the next substep below.
ⓧ I need to install it
macOS
- Click Download for macOS on the VS Code website.
- Open the downloaded .dmg file.
- Drag Visual Studio Code.app to the Applications folder.
- Open VS Code from the Applications folder or Spotlight.
Windows
- Click Download for Windows on the VS Code website.
- Run the downloaded .exe installer.
- Follow the prompts to complete installation.
- VS Code is ready to use. The installer adds code to your PATH so you can open folders from the terminal.
Having trouble installing?
Make sure you're downloading the correct version for your operating system. On macOS, you need macOS 12.0 or higher. On Windows, you need Windows 10 or 11.
Help me troubleshoot my VS Code installation.
Create your project folder
Before writing any code, you need a dedicated folder to keep your project files organized. You'll create this folder on your Desktop so it's easy to find.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Terminal (macOS) or PowerShell (Windows) and press Enter to open it.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder by running this command:
mkdir task-tracker
- Confirm the folder exists by running:
ls
You should see task-tracker listed in the output.
Don't see the folder?
Make sure you typed the folder name exactly as shown, including the hyphen. Folder names are case-sensitive on macOS.
On Windows, if cd ~/Desktop doesn't work, make sure you're using PowerShell (not Command Prompt). PowerShell supports the ~/ shortcut.
Help me create my project folder on the Desktop.
Open the folder in VS Code and create your files
Now you'll open the project folder in VS Code and create the three files your app needs. Each file has a specific job: one for page structure, one for styling, and one for interactivity.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Visual Studio Code and press Enter to open it.
- Click File in the top menu bar.
- Click Open Folder.
- Navigate to your Desktop, select the task-tracker folder, then click Open (macOS) or Select Folder (Windows).
What is the Explorer panel?
After you open the folder, VS Code shows the Explorer panel on the left side. This panel displays all the files and folders in your project. Right now it's empty because you haven't created any files yet.
- In the Explorer panel on the left, hover over the TASK-TRACKER heading to reveal the action icons.
- Click the New File icon (it looks like a page with a plus sign).
- Type index.html and press Enter.
- Click the New File icon again.
- Type style.css and press Enter.
- Click the New File icon one more time.
- Type script.js and press Enter.
You should now see all three files listed in the Explorer panel: index.html, style.css, and script.js.
What are these three files for?
Each file has a specific role in your web app. index.html defines the page structure (headings, buttons, input fields). style.css controls how everything looks (colors, spacing, layout).
script.js adds interactivity (what happens when you click a button or type in a field). Keeping them separate makes your code organized and easier to maintain.
Don't see the New File icon?
Make sure the Explorer panel is open on the left. If you don't see it, click the top icon in the left sidebar (it looks like two overlapping pages) or press Cmd+Shift+E (macOS) or Ctrl+Shift+E (Windows).
The New File icon only appears when you hover over the folder name in the Explorer panel. Make sure you opened the task-tracker folder (not just a single file).
Help me find where to create new files in VS Code.
Your development environment is ready. Next up, you'll write the HTML that gives your task tracker its structure.
Build the HTML Structure
You've got VS Code set up and your project folder ready with three empty files. Now it's time to build the skeleton of your task tracker app.
HTML defines the structure of a web page. Think of it as the bones that hold everything in place. In this step, you'll create the elements your users will see and interact with: a heading, a text input, a button, and a list.
In this step, get ready to:
- Write the HTML structure for your task tracker page.
- Open the page in your browser to see it live.
- Verify everything loaded correctly.
Add the page structure to your HTML file
- In VS Code, click on index.html in the Explorer sidebar to open it.
- Copy the following HTML and paste it into the empty file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Task Tracker</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>Task Tracker</h1>
<div class="input-section">
<input type="text" id="task-input" placeholder="Add a new task...">
<button id="add-btn">Add</button>
</div>
<ul id="task-list"></ul>
</div>
<script src="script.js"></script>
</body>
</html>
What does this code do?
- <!DOCTYPE html> tells the browser this is an HTML5 document.
- The <head> section holds metadata: character encoding, viewport settings for mobile screens, the page title, and a link to your CSS file.
- <div class="container"> wraps all visible content. You'll style this wrapper later with CSS.
- <input id="task-input"> is the text field where users type their tasks. The id gives JavaScript a way to find this element.
- <button id="add-btn"> is the button users click to add a task.
- <ul id="task-list"> is an empty list. JavaScript will add items here each time the user creates a task.
- The <script> tag is placed at the bottom of <body> so the HTML loads before JavaScript runs.
- Save index.html by pressing Cmd+S (macOS) or Ctrl+S (Windows).
Open the page in your browser
Your HTML file can run directly in a browser with no server needed. You just need to open the file from your computer.
- Open the task-tracker folder on your Desktop using Finder (macOS) or File Explorer (Windows).
- Right-click index.html and select Open With > Google Chrome (or Microsoft Edge).
You should see a plain page with the heading "Task Tracker", a text input field, and an "Add" button. It looks unstyled right now. That's completely normal because your CSS file is still empty.
Check that everything loaded correctly
Confirm you can see all three elements on the page: the title, the input field, and the button. If any element is missing, your HTML has a typo somewhere.
Don't see all three elements?
- Check that every opening tag (like <div>) has a matching closing tag (</div>). A missing closing tag can hide the elements below it.
- Make sure you saved index.html after pasting the code. A white dot next to the filename in VS Code means unsaved changes.
- Confirm you opened index.html in the browser, not style.css or script.js.
Why is my HTML page not showing all the elements?
✔️ Awesome, I've got everything!
Great. Double check you've saved your file, then move on to the next step.
ⓧ I'd like to double check the full code
Here's the complete index.html file. Make sure yours matches exactly:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Task Tracker</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>Task Tracker</h1>
<div class="input-section">
<input type="text" id="task-input" placeholder="Add a new task...">
<button id="add-btn">Add</button>
</div>
<ul id="task-list"></ul>
</div>
<script src="script.js"></script>
</body>
</html>
Your page structure is locked in. Next up, you'll add CSS styling to transform this plain page into a polished, centered app.
Style the App with CSS
Your HTML structure is in place and visible in the browser. Right now, though, it looks like a plain document from the 1990s.
In this step, you will add CSS styles to transform the raw HTML into a polished, centered app card. You will style the input area, the button, and prepare styles for task items that JavaScript will create later.
In this step, get ready to:
- Style the page layout and container card.
- Style the input field and Add button.
- Prepare styles for task list items, including a completed state.
Style the page layout and container
Every browser applies its own default spacing and fonts to HTML elements. A CSS reset removes those inconsistencies so your design looks the same everywhere.
- Switch back to VS Code and open style.css from the Explorer panel.
- Add the page layout styles by pasting this code:
/* Remove default browser spacing and use border-box sizing */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Center the app vertically and horizontally */
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
/* White card that holds the entire app */
.container {
background-color: #fff;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
width: 400px;
}
/* Page heading */
h1 {
text-align: center;
margin-bottom: 20px;
color: #333;
}
What does this code do?
The * selector targets every element on the page. Setting margin: 0 and padding: 0 strips away the browser's default spacing.
The body uses Flexbox (display: flex) to center the container both horizontally and vertically. The .container class creates a white card effect with rounded corners and a soft shadow.
- Save style.css.
- Switch to your browser and refresh the page. You should see the heading and input area centered on a light gray background inside a white card.
Still seeing an unstyled page?
- Make sure you saved style.css. Unsaved changes won't appear in the browser.
- Check that index.html has <link rel="stylesheet" href="style.css"> in the <head> section. If this line is missing, the browser cannot find your CSS file.
- Confirm that style.css is in the same folder as index.html. Both files must live inside task-tracker.
Why isn't my CSS showing up in the browser?
Style the input section and button
The input field and button need to sit side by side. Flexbox handles this layout without needing floats or manual positioning.
- In style.css, add the following code below the h1 styles:
/* Place input and button side by side */
.input-section {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
/* Text input stretches to fill available space */
#task-input {
flex: 1;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 16px;
}
/* Green Add button */
#add-btn {
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
cursor: pointer;
}
/* Darken button on hover */
#add-btn:hover {
background-color: #45a049;
}
What does this code do?
The .input-section uses display: flex to lay out the input and button in a row. The gap: 10px adds spacing between them without needing margins.
The flex: 1 on the input tells it to stretch and fill all available space. The button stays its natural width. The :hover style gives visual feedback when the user moves their cursor over the button.
- Save style.css and refresh your browser.
- You should see the input field and green Add button sitting side by side. Hover over the button to confirm it darkens slightly.
Input and button stacked vertically instead of side by side?
- Check that .input-section in your CSS matches class="input-section" in your HTML. Class names are case-sensitive.
- Make sure display: flex is inside the .input-section block, not inside a different selector.
Why are my input and button stacking instead of sitting side by side?
Style the task list items
Tasks do not exist in the HTML yet. JavaScript will create them in the next step. These styles prepare the visual appearance for when tasks are added, completed, and deleted.
- In style.css, add the following code below the #add-btn:hover styles:
/* Remove default bullet points */
#task-list {
list-style: none;
}
/* Each task is a row with space between text and button */
#task-list li {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
border-bottom: 1px solid #eee;
cursor: pointer;
}
/* Subtle highlight when hovering a task */
#task-list li:hover {
background-color: #f9f9f9;
}
/* Strikethrough and gray out completed tasks */
#task-list li.completed span {
text-decoration: line-through;
color: #999;
}
/* Red delete button inside each task */
#task-list li button {
padding: 5px 10px;
background-color: #ff4444;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
font-size: 12px;
}
/* Darken delete button on hover */
#task-list li button:hover {
background-color: #cc0000;
}
What does this code do?
The #task-list li styles make each task a flex row with the task text on the left and the delete button pushed to the right using justify-content: space-between.
The .completed class applies a strikethrough (text-decoration: line-through) to finished tasks. JavaScript will toggle this class on and off when you click a task.
- Save style.css.
You will not see the task list styles yet because there are no tasks to display. These styles take effect once you add tasks with JavaScript in the next step.
✔️ Awesome, I've got everything!
Great. Double check you have saved style.css and your browser shows the styled card.
ⓧ I'd like to double check the full code
Here is the complete style.css file. Compare yours against it:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.container {
background-color: #fff;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
width: 400px;
}
h1 {
text-align: center;
margin-bottom: 20px;
color: #333;
}
.input-section {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
#task-input {
flex: 1;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 16px;
}
#add-btn {
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
cursor: pointer;
}
#add-btn:hover {
background-color: #45a049;
}
#task-list {
list-style: none;
}
#task-list li {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
border-bottom: 1px solid #eee;
cursor: pointer;
}
#task-list li:hover {
background-color: #f9f9f9;
}
#task-list li.completed span {
text-decoration: line-through;
color: #999;
}
#task-list li button {
padding: 5px 10px;
background-color: #ff4444;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
font-size: 12px;
}
#task-list li button:hover {
background-color: #cc0000;
}
Your app looks polished and ready for action. Next up, you will bring it to life by writing JavaScript that adds tasks to the list.
Add Tasks with JavaScript
Your app looks great, but clicking the Add button does nothing. That's because HTML and CSS only handle structure and appearance. JavaScript is the language that makes your page respond to user actions.
In this step, you'll write JavaScript that grabs elements from the page, listens for button clicks, and dynamically creates new task items in the list. This pattern of selecting elements and responding to events is the foundation of every interactive website.
In this step, get ready to:
- Select HTML elements from the page using JavaScript.
- Create an event listener that adds tasks when you click the button.
- Add Enter key support and test the app.
Select the HTML elements
Before JavaScript can change anything on the page, it needs a reference to the elements it will work with. The DOM (Document Object Model) is the browser's representation of your HTML. You use selectors to grab specific elements from it.
- In VS Code, open script.js from the Explorer panel on the left.
- Add the following code to select the three elements your app needs:
// Select the input field, button, and task list from the page
const input = document.querySelector("#task-input");
const addBtn = document.querySelector("#add-btn");
const taskList = document.querySelector("#task-list");
What does this code do?
document.querySelector() searches the page for an element matching a CSS selector and returns it. The # symbol means you're selecting by ID, just like in CSS.
const creates a variable that cannot be reassigned. Each variable stores a reference to one HTML element so you can use it later in your code.
- Save script.js.
- Switch to your browser and open the developer console by pressing Cmd+Option+J (macOS) or Ctrl+Shift+J (Windows).
- Refresh the page. If you see no errors in the console, your selectors are working correctly.
Seeing an error in the console?
- Check that the IDs in your JavaScript (#task-input, #add-btn, #task-list) match the IDs in your index.html exactly.
- Make sure script.js is saved. Unsaved changes won't run in the browser.
- Confirm the <script src="script.js"></script> tag is at the bottom of the <body> in your HTML file.
Why can't JavaScript find my elements?
Create the click event listener
An event listener tells the browser to run a function whenever something specific happens, like a click. You'll attach one to the Add button so it creates a new task every time the button is clicked.
- In script.js, add this code below the three const variables:
addBtn.addEventListener("click", function() {
// Read the text the user typed and remove extra spaces
const taskText = input.value.trim();
// If the input is empty, stop here
if (taskText === "") {
return;
}
// Create a new list item element
const listItem = document.createElement("li");
// Create a span to hold the task text
const span = document.createElement("span");
span.textContent = taskText;
listItem.appendChild(span);
// Create a delete button for this task
const deleteBtn = document.createElement("button");
deleteBtn.textContent = "Delete";
listItem.appendChild(deleteBtn);
// Add the new task to the list and clear the input
taskList.appendChild(listItem);
input.value = "";
input.focus();
});
What does this code do?
- addEventListener("click", function() {...}) attaches a function to the button that runs every time you click it.
- input.value.trim() reads whatever text the user typed and strips whitespace from both ends.
- The if (taskText === "") check prevents empty tasks from being added.
- document.createElement() builds new HTML elements in memory. You set their content, then use appendChild() to attach them to the page.
- input.focus() moves the cursor back to the input field so the user can immediately type another task.
- Save script.js.
- Refresh your browser and type Buy groceries in the input field, then click Add.
- You should see "Buy groceries" appear in the list below with a red Delete button next to it.
Task not appearing when you click Add?
- Check for typos in addEventListener. The event name must be "click" (lowercase, in quotes).
- Make sure every opening brace { has a matching closing brace } and every opening parenthesis ( has a matching ). Missing brackets are the most common JavaScript error for beginners.
- Open the browser console (Cmd+Option+J / Ctrl+Shift+J) to see if there's an error message pointing to the problem line.
Help me debug my addEventListener code.
Add Enter key support and test
Most users expect to press Enter after typing a task instead of reaching for the mouse. You can listen for keyboard events the same way you listen for clicks.
- In script.js, add this code below the closing }); of the click listener:
// Let the user press Enter to add a task
input.addEventListener("keydown", function(event) {
if (event.key === "Enter") {
addBtn.click();
}
});
What does this code do?
This listens for any key press inside the input field. When the pressed key is Enter, it programmatically clicks the Add button. This reuses your existing click handler instead of duplicating the task-creation logic.
- Save script.js and refresh your browser.
- Type Walk the dog and press Enter. The task should appear in the list without clicking the button.
- Try adding 3-4 more tasks using both the button and the Enter key. Each task should appear below the previous one.
- Try clicking Add with an empty input. Nothing should happen.
Enter key not working?
- Make sure the second addEventListener is attached to input, not addBtn. The keyboard event needs to fire on the element where you're typing.
- Check that event.key === "Enter" uses a capital E. Key names are case-sensitive.
Why isn't my keydown listener working?
✔️ Awesome, I've got everything!
Great. Double check you've saved script.js before moving on.
ⓧ I'd like to double check the full code
Here is the complete script.js file so far. Compare it to yours and fix any differences.
const input = document.querySelector("#task-input");
const addBtn = document.querySelector("#add-btn");
const taskList = document.querySelector("#task-list");
addBtn.addEventListener("click", function() {
const taskText = input.value.trim();
if (taskText === "") {
return;
}
const listItem = document.createElement("li");
const span = document.createElement("span");
span.textContent = taskText;
listItem.appendChild(span);
const deleteBtn = document.createElement("button");
deleteBtn.textContent = "Delete";
listItem.appendChild(deleteBtn);
taskList.appendChild(listItem);
input.value = "";
input.focus();
});
input.addEventListener("keydown", function(event) {
if (event.key === "Enter") {
addBtn.click();
}
});
Your app can now create tasks dynamically. Next up, you'll make those tasks interactive by adding the ability to mark them complete and delete them.
Mark Tasks Complete and Delete Them
Your task tracker can add tasks to the list, but clicking them does nothing. A real task app needs two more interactions: marking tasks as done and removing tasks you no longer need.
In this step, you'll wire up event listeners to each task so clicking the task text toggles a strikethrough effect. You'll also make the Delete button remove tasks from the list entirely.
In this step, get ready to:
- Add a click event listener that marks tasks complete with a strikethrough.
- Add a click event listener that deletes tasks from the list.
- Test the full app to confirm all features work together.
Add a click listener to toggle the completed class
When a user clicks a task, they expect it to look "done." Your style.css already has a .completed class that applies a strikethrough. You just need JavaScript to toggle that class on and off when the task text is clicked.
- In script.js, find the line that says listItem.appendChild(deleteBtn); inside your addBtn click listener.
- Add the following code directly below that line:
// Toggle the 'completed' class when the task text is clicked
span.addEventListener("click", function() {
listItem.classList.toggle("completed");
});
What does this code do?
This attaches a click event listener to the span element (the task text). Every time it's clicked, classList.toggle("completed") adds the completed class if it's missing, or removes it if it's already there.
Your CSS rule #task-list li.completed span applies text-decoration: line-through whenever that class is present. So toggling the class toggles the strikethrough effect.
- Save script.js.
- Refresh your browser and add a task (e.g. Buy milk). Click the task text. You should see a strikethrough appear on the text and the colour turn grey.
- Click the task text again. The strikethrough disappears and the text returns to normal.
Clicking the task does nothing?
- Make sure you saved script.js before refreshing.
- Check that the listener is attached to span, not listItem. Clicking the Delete button area shouldn't toggle the class.
- Confirm the class name in your JavaScript ("completed") matches the CSS selector (.completed) exactly.
Why isn't classList.toggle applying my strikethrough style?
Wire up the delete button
Each task already has a red Delete button from the previous step, but clicking it does nothing yet. You need an event listener that removes the entire task from the list when that button is clicked.
- In script.js, find the span event listener you just added. Add this code directly below its closing });:
// Remove the task from the list when Delete is clicked
deleteBtn.addEventListener("click", function() {
taskList.removeChild(listItem);
});
What does this code do?
This attaches a click listener to the deleteBtn element. When clicked, taskList.removeChild(listItem) tells the parent <ul> to remove the entire <li> (including its text and delete button) from the page.
- Save script.js.
- Refresh your browser and add a task. Click the red **Delete** button next to it. The task disappears from the list entirely.
Delete button not removing the task?
- Make sure you wrote taskList.removeChild(listItem) and not taskList.removeChild(deleteBtn). You want to remove the whole list item, not just the button.
- Check that the listener is on deleteBtn, not on span. If both listeners are on span, clicking the text will remove the task instead of toggling it.
Why is removeChild not working on my task list?
Test the full app
All three features of your task tracker are now working. Time to run through every interaction and confirm the full experience is solid.
- Refresh your browser.
- Type a task (e.g. Walk the dog) and click Add. The task appears in the list below.
- Add two or three more tasks so you have a list to work with.
- Click a task's text. The strikethrough and grey colour appear.
- Click the same task's text again. The strikethrough disappears.
- Click a task's Delete button. The task is removed from the list.
- Leave the input field empty and click Add. Nothing should happen because the empty input guard prevents blank tasks from being added.
Why does the empty input check work?
Your code from the previous step trims whitespace with input.value.trim() and checks if the result is an empty string. If it is, return exits the function immediately. This prevents blank tasks or whitespace-only tasks from being added to the list.
✔️ Awesome, I've got everything!
Great. Double check you've saved script.js and all three interactions work: adding, completing, and deleting.
ⓧ I'd like to double check the full code
Here's the complete script.js file. Compare it against yours line by line.
const input = document.querySelector("#task-input");
const addBtn = document.querySelector("#add-btn");
const taskList = document.querySelector("#task-list");
addBtn.addEventListener("click", function() {
const taskText = input.value.trim();
if (taskText === "") {
return;
}
const listItem = document.createElement("li");
const span = document.createElement("span");
span.textContent = taskText;
listItem.appendChild(span);
const deleteBtn = document.createElement("button");
deleteBtn.textContent = "Delete";
listItem.appendChild(deleteBtn);
span.addEventListener("click", function() {
listItem.classList.toggle("completed");
});
deleteBtn.addEventListener("click", function() {
taskList.removeChild(listItem);
});
taskList.appendChild(listItem);
input.value = "";
input.focus();
});
input.addEventListener("keydown", function(event) {
if (event.key === "Enter") {
addBtn.click();
}
});
Secret mission
Task Counter and localStorage Persistence
Your task tracker works great, but there's a problem. Every time you refresh the page, all your tasks disappear. In this secret mission, you'll add a live counter that shows how many tasks are left, and you'll make your tasks survive a page refresh using localStorage.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally, so there are no ongoing costs. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- The task-tracker folder on your Desktop (contains index.html, style.css, and script.js).
- localStorage data saved by the task tracker in your browser.
- Visual Studio Code (installed in Step 1).
Keep everything running
No action needed. Choose this if you're still actively building or plan to extend the task tracker with more features.
- Your task-tracker folder stays on your Desktop, ready for future edits.
- Your saved tasks remain in the browser's localStorage until you clear them.
- Visual Studio Code stays installed for any future coding projects.
Pause - I'll come back to this later
Since this project runs entirely on your computer, there is nothing consuming resources while you are away. Your files and saved tasks will remain exactly where they are.
- Close the browser tab showing your task tracker.
- Close Visual Studio Code.
- When you are ready to come back, open index.html in your browser again. Your tasks will still be there thanks to localStorage.
Delete - I don't want to use this again
Remove all project resources and start fresh. Follow each step below to fully clean up.
- Delete the project folder. On macOS/Linux, open Terminal and run the command below. On Windows, open PowerShell and run the second command.
rm -rf ~/Desktop/task-tracker
Remove-Item -Recurse -Force "$HOME\Desktop\task-tracker"
- Clear localStorage data. Open Google Chrome, press F12 to open DevTools, click the Console tab, and run this command:
localStorage.removeItem("tasks")
- Uninstall Visual Studio Code (optional). On Windows, open Settings, select Apps, find Microsoft Visual Studio Code, and click Uninstall. On macOS, open Finder, go to Applications, and drag Visual Studio Code to the Trash.
Nice Work!
Nice Work!
You just built your first interactive web app from scratch using vanilla JavaScript. Your task tracker handles adding, completing, and deleting tasks with zero frameworks and zero build tools.
You've learned how to:
- Built a complete web app with HTML structure, CSS styling, and JavaScript logic working together across three separate files.
- Used document.querySelector(), addEventListener(), and document.createElement() to select elements, respond to user clicks, and dynamically build content on the page.
- Used classList.toggle() to change an element's appearance and removeChild() to delete elements from the DOM.
- Secret Mission: Added a live task counter and persistent storage with localStorage so tasks survive a page refresh.
Ready to quiz yourself?