Introduction:
In JavaScript, a To-Do App is a beginner-level project for new developers. If you want to learn JavaScript, you should join this app as it helps to master JavaScript concepts. If the developers make this project, you can easily create large projects such as a job portal website, a Movie game, etc.
In this article, we’ll learn to build a To-Do app using Vanilla JavaScript without any external frameworks and libraries. This helps to show how to work JavaScript with HTML and CSS. With the use of this project, users perform these operations such as adding new tasks, updating tasks, deleting tasks and saving data in local devices.
Why Build a To-Do App?
Building a To-Do app using Vanilla JavaScript is a powerful learning web development. Some of the reasons are as follows:
• All fundamental Concepts: To-Do app includes the major topics of modern web applications, such as Event handling, DOM manipulation, managing local storage, etc.
• Prepares you for Larger Projects: If the developers create this project, you should prepare for building large projects such as an E-commerce website, CRUD operations, etc.
• Understand how a website works: In the learning phase, you are creating this project to help how websites work, like HTML used to build the structure, CSS add how to show your interactive page, and JavaScript used to make it a dynamic website.
Build A To-Do App
Step 1) Add the HTML (index.html) file:
<!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 App</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<h1>📝 To-Do List</h1>
<div class="input-group">
<input type="text" id="task-input" placeholder="Add a task..." />
<button id="add-btn">Add</button>
</div>
<ul id="task-list"></ul>
</div>
<script src="script.js"></script>
</body>
</html>
Step 2) Add the CSS (style.css) file:
/* Global Styles */
body {
font-family: Arial, sans-serif;
background: #f3f3f3;
display: flex;
justify-content: center;
padding-top: 60px;
margin: 0;
}
/* Container Box */
.container {
background: #fff;
padding: 30px;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
width: 400px;
}
/* Heading */
h1 {
text-align: center;
margin-bottom: 20px;
}
/* Input & Button Section */
.input-group {
display: flex;
gap: 10px;
}
#task-input {
flex: 1;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
}
#add-btn {
padding: 10px;
background: #28a745;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
#add-btn:hover {
background: #218838;
}
/* Task List */
ul {
list-style: none;
padding: 0;
margin-top: 20px;
}
li {
background: #f8f9fa;
padding: 12px;
margin-bottom: 10px;
border-radius: 5px;
display: flex;
flex-direction: column;
gap: 8px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
}
/* Completed Task Style */
li.completed .task-title {
text-decoration: line-through;
color: #888;
}
/* Task Header Row */
.task-top-row {
display: flex;
justify-content: space-between;
align-items: center;
}
/* Text */
.task-title {
font-weight: bold;
font-size: 1rem;
color: #222;
cursor: pointer;
}
/* Time Info */
.task-info {
font-size: 0.75rem;
color: #666;
}
/* Buttons Section */
button.edit,
button.delete {
padding: 8px;
border: none;
border-radius: 4px;
cursor: pointer;
flex: 1;
}
button.edit {
background-color: #ffc107;
color: black;
}
button.edit:hover {
background-color: #e0a800;
}
button.delete {
background: crimson;
color: white;
}
button.delete:hover {
background: darkred;
}
.task-buttons {
display: flex;
gap: 10px;
}
/* Responsive */
@media screen and (max-width: 450px) {
.container {
width: 90%;
}
.task-top-row {
flex-direction: column;
align-items: flex-start;
gap: 4px;
}
.task-buttons {
flex-direction: column;
}
}
Step 3) Add JavaScript(script.js) file:
const taskInput = document.getElementById("task-input");
const addBtn = document.getElementById("add-btn");
const taskList = document.getElementById("task-list");
// Load tasks from localStorage on page load
window.addEventListener("DOMContentLoaded", () => {
const tasks = JSON.parse(localStorage.getItem("tasks")) || [];
tasks.forEach(task => {
createTaskElement(task.text, task.completed, task.addedAt, task.updatedAt);
});
});
// Add new task
addBtn.addEventListener("click", () => {
const taskText = taskInput.value.trim();
if (taskText !== "") {
const now = new Date().toLocaleString();
createTaskElement(taskText, false, now, now);
saveTask(taskText, false, now, now);
taskInput.value = "";
}
});
// Create and display a task element
function createTaskElement(text, completed = false, addedAt = "", updatedAt = "") {
const li = document.createElement("li");
if (completed) li.classList.add("completed");
// Task text span
const span = document.createElement("span");
span.textContent = text;
span.className = "task-title";
span.addEventListener("click", () => {
li.classList.toggle("completed");
updateTaskStatus(text);
});
// Time Info
const timeInfo = document.createElement("small");
timeInfo.className = "task-info";
timeInfo.textContent = `Added: ${addedAt}${updatedAt !== addedAt ? ` | Updated: ${updatedAt}` : ""}`;
// Top row (task + time)
const topRow = document.createElement("div");
topRow.className = "task-top-row";
topRow.appendChild(span);
topRow.appendChild(timeInfo);
// Buttons
const editBtn = document.createElement("button");
editBtn.textContent = "Edit";
editBtn.className = "edit";
editBtn.addEventListener("click", () => {
const newText = prompt("Edit your task:", span.textContent);
if (newText && newText.trim() !== "") {
editTask(text, newText.trim());
}
});
const deleteBtn = document.createElement("button");
deleteBtn.textContent = "Delete";
deleteBtn.className = "delete";
deleteBtn.addEventListener("click", () => {
li.remove();
removeTask(text);
});
const btnRow = document.createElement("div");
btnRow.className = "task-buttons";
btnRow.appendChild(editBtn);
btnRow.appendChild(deleteBtn);
li.appendChild(topRow);
li.appendChild(btnRow);
taskList.appendChild(li);
}
// Save a new task to localStorage
function saveTask(text, completed, addedAt, updatedAt) {
const tasks = JSON.parse(localStorage.getItem("tasks")) || [];
tasks.push({ text, completed, addedAt, updatedAt });
localStorage.setItem("tasks", JSON.stringify(tasks));
}
// Toggle complete/incomplete and update timestamp
function updateTaskStatus(text) {
let tasks = JSON.parse(localStorage.getItem("tasks")) || [];
const now = new Date().toLocaleString();
tasks = tasks.map(task =>
task.text === text
? { ...task, completed: !task.completed, updatedAt: now }
: task
);
localStorage.setItem("tasks", JSON.stringify(tasks));
reloadTasks();
}
// Edit task text and update timestamp
function editTask(oldText, newText) {
let tasks = JSON.parse(localStorage.getItem("tasks")) || [];
const now = new Date().toLocaleString();
tasks = tasks.map(task =>
task.text === oldText
? { ...task, text: newText, updatedAt: now }
: task
);
localStorage.setItem("tasks", JSON.stringify(tasks));
reloadTasks();
}
// Remove task from localStorage
function removeTask(text) {
let tasks = JSON.parse(localStorage.getItem("tasks")) || [];
tasks = tasks.filter(task => task.text !== text);
localStorage.setItem("tasks", JSON.stringify(tasks));
}
// Refresh list from localStorage
function reloadTasks() {
taskList.innerHTML = "";
loadTasks();
}
// Re-render all tasks from storage
function loadTasks() {
const tasks = JSON.parse(localStorage.getItem("tasks")) || [];
tasks.forEach(task =>
createTaskElement(task.text, task.completed, task.addedAt, task.updatedAt)
);
}
Output:
Conclusion
To-Do App provides features for you to add your task, edit and update task as well. This app is created using Vanilla JavaScript provides core web development skills. It supports how to manipulate the DOM, handle events and manage the local Storage without the use of any frameworks and libraries. Clean HTML structure combined with CSS style shows its power.
I suggest you learn JavaScript programming from the Tpoint tech website, as it provides JavaScript Tutorials, interview questions, and all its related topics in easier way.
Top comments (0)