A to-do list is one of the most common beginner projects — but what if we take it to the next level?
In this blog, we’ll break down an Advanced To-Do List App that includes:
Task creation
Deadline picker
Live countdown timer for each task
Task editing
Task deletion
LocalStorage saving
Light/Dark theme toggle
Task filters (All, Active, Completed)
Content Table
- 1. App Overview
- Explanation of the To-Do List HTML Code
- HTML Structure Overview
- Line-by-Line Breakdown
- In Simple Words
- CSS File Explanation (Line-by-Line / Section-by-Section)
- 1. Google Font Import
- 2. CSS Variables (Global Theme Colors)
- 3. Reset Styles
- 4. Body Styling
- 5. App Container
- 6. Top Bar
- 7. Theme Toggle Button
- 8. Input Section
- 9. Add Button
- 10. Filters (All / Active / Completed)
- 11. Task List Styling
- 12. Each Task Item (Card)
- 13. Task Actions (Edit/Delete Buttons)
- 14. Deadline & Countdown Styles
- 15. Clear All Button
- 16. Animations
- 17. Responsive Design
- Summary
- FULL EXPLANATION OF YOUR JAVASCRIPT CODE
- TOP — Selecting All Required Elements
- DOM Loaded Event
- Button Events
- Add Task on Enter Key
- Open Datetime Picker When Clicking Input
- FUNCTION: addTask() — Adding a new task
- FUNCTION: createTaskElement() — Builds the task UI
- saveTasks() — Stores tasks in LocalStorage
- loadTasks() — Loads tasks from LocalStorage
- Clear All Tasks
- Filtering Tasks (All / Active / Completed)
- Dark/Light Theme Toggle
- Countdown Timer Function
- This app includes:
1. App Overview
This app is built using:
- HTML → Layout structure
- CSS → Styling (light/dark mode included)
- JavaScript → Task management, countdown timer, theme switching
- LocalStorage → Save tasks permanently
Explanation of the To-Do List HTML Code
This code creates the structure of an advanced To-Do List App with task input, deadlines, theme toggle, filters, and actions.
HTML Structure Overview
Your file includes:
- Page header information
- A container (
.app) that holds the entire UI - Input fields for task and deadline
- Filter buttons
- Task list area
- Clear-all button
- External CSS + JS links
Line-by-Line Breakdown
1. Basic HTML Setup
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Advanced To-Do App with Deadlines</title>
<link rel="stylesheet" href="style.css">
What this means:
<!DOCTYPE html>→ Defines modern HTML5.<html lang="en">→ Page language is English.<meta charset="UTF-8">→ Supports all characters (Hindi, Emojis, etc.)<meta name="viewport">→ Makes page responsive (mobile-friendly).<title>→ Name shown in browser tab.<link rel="stylesheet" href="style.css">→ Connects external CSS file.
2. Font Awesome Icons
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css">
Used for icons like ✔, ✖, 🗑, etc.
Here it’s used for the title icon.
3. App Container
<div class="app">
Everything in your app is wrapped inside this main container.
4. Top Bar (Header)
<div class="top-bar">
<h1><i class="fa-solid fa-table-list"></i> To-Do List</h1>
<button id="theme-toggle" type="button" aria-label="Toggle theme">🌙</button>
</div>
Consists of:
- A heading with an icon
- A theme toggle button (dark/light mode)
The aria-label improves accessibility (for screen readers).
5. Task Input Section
<div class="input-box">
<div class="input-group">
<label for="task-input">Task</label>
<input type="text" id="task-input" placeholder="What needs to be done?">
</div>
<div class="input-group">
<label for="task-deadline">Deadline</label>
<input type="datetime-local" id="task-deadline">
</div>
<button id="add-btn" type="button">Add</button>
</div>
What it contains:
✔ Task input — user types task
✔ Deadline input — user selects date & time
✔ Add button — JavaScript will add the task to the list
Both input groups have <label> for accessibility.
6. Filters (All / Active / Completed)
<div class="filters" role="group">
<button class="filter active" data-filter="all">All</button>
<button class="filter" data-filter="active">Active</button>
<button class="filter" data-filter="completed">Completed</button>
</div>
Filters help users view:
- All tasks
- Active tasks (not completed)
- Completed tasks
data-filter is used in JavaScript to know which filter was clicked.
7. Task List Container
<ul id="task-list" aria-live="polite"></ul>
This is where JavaScript will dynamically show tasks as list items:
- With checkboxes
- With delete buttons
- With deadline countdown
aria-live="polite" → Screen readers announce updates automatically.
8. Clear All Button
<div class="actions">
<button id="clear-all" type="button">Clear All</button>
</div>
This removes all tasks (handled in JS).
9. External JavaScript File
<script src="script.js"></script>
All logic (add task, delete, update theme, filters, storing tasks in localStorage) will be written in script.js.
In Simple Words
This HTML creates:
| Feature | Purpose |
|---|---|
| Header + theme button | Switch between light and dark modes |
| Task input | Enter new tasks |
| Deadline input | Set due date/time |
| Add button | Add tasks dynamically |
| Filters | Show only specific tasks |
| Task list | Display tasks created by JS |
| Clear all | Quickly remove everything |
CSS File Explanation (Line-by-Line / Section-by-Section)
Your CSS contains:
- Google Font
- Theme variables
- Reset
- Layout (body, containers)
- Theme Dark Mode support
- Input styling
- Filter styling
- Task list styling
- Buttons
- Animations
- Responsive design
Let’s break it down.
1. Google Font Import
@import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');
This loads the Poppins font from Google.
Your entire app uses this font.
2. CSS Variables (Global Theme Colors)
:root {
--primary: #4facfe;
--secondary: #00fefe;
--danger: #ff4d4d;
--warning: #ffb347;
--bg-light: rgba(255, 255, 255, 0.7);
--bg-dark: rgba(0, 0, 0, 0.45);
--text-dark: #222;
--text-light: #fff;
}
These are CSS variables, which act like reusable values.
Examples:
--primary= main blue color--danger= delete/red color--bg-light= white frosted glass--bg-dark= dark frosted glass for dark mode
Using variables makes theme switching easy.
3. Reset Styles
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
transition: all 0.3s ease;
}
This:
- Removes default browser margin/padding
- Ensures consistent sizing
- Applies font globally
- Adds smooth animation for theme changes
4. Body Styling
body {
min-height: 100vh;
background: linear-gradient(135deg, var(--primary), var(--secondary));
display: flex;
align-items: center;
justify-content: center;
color: var(--text-dark);
}
This gives:
✔ Full page gradient
✔ Centers the app vertically & horizontally
✔ Light mode text color
Dark mode version:
body.dark {
background: linear-gradient(135deg, #141e30, #243b55);
color: var(--text-light);
}
When body gets class "dark" (via JS), background & text change.
5. App Container
.app {
width: 450px;
background: var(--bg-light);
backdrop-filter: blur(20px);
padding: 2rem;
border-radius: 24px;
box-shadow: 0 10px 35px rgba(0,0,0,0.2);
}
This gives your app a glassmorphism look:
- Frosted blur
- Rounded corners
- Shadow
Dark mode version:
body.dark .app {
background: var(--bg-dark);
}
6. Top Bar
.top-bar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.8rem;
}
Aligns the heading and theme-toggle button in a row.
The heading has a color gradient using background-clip.
7. Theme Toggle Button
#theme-toggle {
font-size: 1.4rem;
background: transparent;
border: none;
cursor: pointer;
}
Dark mode recolors it automatically:
body.dark #theme-toggle {
color: var(--text-light);
}
8. Input Section
.input-box {
display: flex;
flex-direction: column;
gap: 0.8rem;
}
Makes all inputs stacked vertically with spacing.
Labels
label {
font-size: 0.9rem;
font-weight: 500;
}
Input Fields
#task-input, #task-deadline {
padding: 0.75rem 1rem;
border-radius: 12px;
background: rgba(255, 255, 255, 0.7);
}
Dark mode:
body.dark #task-input, body.dark #task-deadline {
background: rgba(0,0,0,0.3);
color: #fff;
}
9. Add Button
#add-btn {
padding: 0.8rem;
border-radius: 12px;
background: linear-gradient(135deg, var(--primary), var(--secondary));
color: #fff;
cursor: pointer;
}
Hover effect:
#add-btn:hover {
transform: scale(1.05);
box-shadow: 0 4px 10px rgba(79, 172, 254, 0.5);
}
10. Filters (All / Active / Completed)
.filters {
display: flex;
justify-content: center;
gap: 0.6rem;
}
Each filter button:
.filter {
padding: 0.45rem 0.9rem;
border-radius: 20px;
}
Active filter highlighted:
.filter.active {
background: linear-gradient(135deg, var(--primary), var(--secondary));
color: white;
}
Dark mode styling provided as well.
11. Task List Styling
Container:
#task-list {
max-height: 260px;
overflow-y: auto;
}
Scrolling bar is custom styled.
12. Each Task Item (Card)
#task-list li {
background: rgba(255,255,255,0.3);
padding: 1rem;
border-radius: 14px;
margin-bottom: 0.8rem;
animation: slideUp 0.4s ease;
}
Dark version provided too.
Completed tasks:
#task-list li.completed {
opacity: 0.7;
text-decoration: line-through;
}
13. Task Actions (Edit/Delete Buttons)
.task-actions {
position: absolute;
top: 10px;
right: 10px;
}
Buttons appear only on hover:
.edit-btn, .delete-btn {
opacity: 0;
}
#task-list li:hover .edit-btn,
#task-list li:hover .delete-btn {
opacity: 1;
}
14. Deadline & Countdown Styles
.deadline {
font-size: 0.85rem;
color: #555;
}
.green-timer { color: #00c853; }
.warning { color: var(--warning); }
.overdue { color: var(--danger); }
Colors indicate urgency.
15. Clear All Button
#clear-all {
padding: 0.6rem 1rem;
border-radius: 10px;
background: rgba(255,255,255,0.2);
}
Hover turns red:
#clear-all:hover {
background: var(--danger);
color: #fff;
}
16. Animations
@keyframes fadeIn { opacity: 0 → 1 }
@keyframes slideUp { translateY(15px) → 0 }
These make items appear smoothly.
17. Responsive Design
@media (max-width: 480px) {
.app { width: 90%; }
}
This makes the UI mobile-friendly.
Summary
Your CSS:
- Creates a beautiful glassmorphic UI
- Supports dark mode
- Styles inputs, buttons, filters, tasks
- Adds animations & responsiveness
- Provides color-coded countdowns
- Makes action buttons show only on hover
If you want, I can also explain your JavaScript, or create a fully working script.js with:
✔ Add tasks
✔ Delete tasks
✔ Edit tasks
✔ Mark complete
✔ Countdown Timer
✔ Save to LocalStorage
✔ Dark Mode toggle
FULL EXPLANATION OF YOUR JAVASCRIPT CODE
TOP — Selecting All Required Elements
const taskInput = document.getElementById('task-input');
const deadlineInput = document.getElementById('task-deadline');
const addBtn = document.getElementById('add-btn');
const taskList = document.getElementById('task-list');
const clearAllBtn = document.getElementById('clear-all');
const themeToggle = document.getElementById('theme-toggle');
const filters = document.querySelectorAll('.filter');
What this does:
You store all important HTML elements inside variables so you can use them easily later.
Example:
taskInput→ the task text boxdeadlineInput→ the deadline inputaddBtn→ the Add buttontaskList→ the<ul>where tasks will appearfilters→ All filter buttons (All, Active, Completed)
DOM Loaded Event
document.addEventListener('DOMContentLoaded', () => {
loadTasks();
loadTheme();
startCountdownUpdater();
});
This runs when the page fully loads.
It does three things:
- loadTasks() → gets saved tasks from localStorage
- loadTheme() → loads saved light/dark theme
- startCountdownUpdater() → updates countdown timers every second
Button Events
addBtn.addEventListener('click', addTask);
clearAllBtn.addEventListener('click', clearAllTasks);
themeToggle.addEventListener('click', toggleTheme);
These connect buttons to functions.
Add Task on Enter Key
taskInput.addEventListener('keypress', e => {
if(e.key === 'Enter') addBtn.click();
});
If user presses Enter, it works like clicking Add.
Open Datetime Picker When Clicking Input
deadlineInput.addEventListener('click', () => {
if (typeof deadlineInput.showPicker === 'function') {
deadlineInput.showPicker();
}
});
This automatically opens the date-time selector popup when user clicks.
FUNCTION: addTask() — Adding a new task
function addTask() {
const taskText = taskInput.value.trim();
const deadline = deadlineInput.value;
if (!taskText) return alert('Please enter a task!');
if (!deadline) return alert('Please set a deadline');
const li = createTaskElement(taskText, false, deadline);
taskList.appendChild(li);
saveTasks();
taskInput.value = '';
deadlineInput.value = '';
}
This function does:
- Reads text & deadline
- Validates them
- Creates a list item (
<li>) usingcreateTaskElement() - Adds it to the task list
- Saves to localStorage
- Clears input boxes
FUNCTION: createTaskElement() — Builds the task UI
THIS IS THE HEART OF THE APP.
It creates everything inside a task box:
- Text
- Deadline
- Countdown timer
- Edit button
- Delete button
I’ll explain step by step.
1. Create <li> and add text
const li = document.createElement('li');
li.deadline = deadline;
Stores deadline inside the <li> object.
Task Text
const taskSpan = document.createElement('span');
taskSpan.textContent = text;
taskSpan.classList.add('task-text');
If completed, strike-through:
if(completed) li.classList.add('completed');
Deadline Display
const deadlineDiv = document.createElement('div');
deadlineDiv.classList.add('deadline');
deadlineDiv.textContent = `📅 ${new Date(deadline).toLocaleString()}`;
When you type 2025-03-01T16:00, it converts it into readable time.
Countdown Timer Element
const countdownDiv = document.createElement('div');
countdownDiv.classList.add('countdown','green-timer');
li.appendChild(countdownDiv);
Clicking Task = Toggle Completed
taskSpan.addEventListener('click', () => {
li.classList.toggle('completed');
saveTasks();
});
EDIT Button
const editBtn = document.createElement('button');
editBtn.innerHTML = '✏️';
When clicked:
const newText = prompt('Edit your task:', currentText);
const newDeadline = prompt('Edit deadline (YYYY-MM-DDTHH:MM)', currentDeadline);
Then updates text + UI + saves tasks.
DELETE Button
delBtn.addEventListener('click', e => {
e.stopPropagation();
li.remove();
saveTasks();
});
Deletes the task completely.
saveTasks() — Stores tasks in LocalStorage
function saveTasks() {
const tasks = [];
document.querySelectorAll('#task-list li').forEach(li => {
tasks.push({
text: li.querySelector('.task-text').textContent,
completed: li.classList.contains('completed'),
deadline: li.deadline
});
});
localStorage.setItem('tasks', JSON.stringify(tasks));
}
Saves all tasks in an array of objects:
[
{ "text": "Study", "completed": false, "deadline": "2025-03-01T18:00" }
]
loadTasks() — Loads tasks from LocalStorage
function loadTasks() {
const saved = JSON.parse(localStorage.getItem('tasks')) || [];
saved.forEach(t => taskList.appendChild(createTaskElement(t.text, t.completed, t.deadline)));
applyFilter('all');
}
—
Clear All Tasks
function clearAllTasks() {
if(confirm('Are you sure?')){
taskList.innerHTML = '';
localStorage.removeItem('tasks');
}
}
Filtering Tasks (All / Active / Completed)
filters.forEach(btn => {
btn.addEventListener('click', () => {
filters.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
applyFilter(btn.dataset.filter);
});
});
The filter logic:
function applyFilter(filter) {
const items = document.querySelectorAll('#task-list li');
items.forEach(item => {
switch(filter) {
case 'all': item.style.display = 'flex'; break;
case 'active': item.style.display = item.classList.contains('completed') ? 'none' : 'flex'; break;
case 'completed': item.style.display = item.classList.contains('completed') ? 'flex' : 'none'; break;
}
});
}
Dark/Light Theme Toggle
function toggleTheme() {
document.body.classList.toggle('dark');
const darkMode = document.body.classList.contains('dark');
themeToggle.textContent = darkMode ? '☀️' : '🌙';
localStorage.setItem('theme', darkMode ? 'dark' : 'light');
}
Loads saved theme:
function loadTheme() {
const theme = localStorage.getItem('theme');
if(theme === 'dark') {
document.body.classList.add('dark');
themeToggle.textContent = '☀️';
}
}
Countdown Timer Function
Runs every 1 second:
function startCountdownUpdater() {
setInterval(() => {
document.querySelectorAll('#task-list li').forEach(li => {
const countdownDiv = li.querySelector('.countdown');
const deadline = new Date(li.deadline);
const now = new Date();
const diff = deadline - now;
If deadline passed:
if(diff <= 0){
countdownDiv.textContent = 'Overdue!';
countdownDiv.classList.add('overdue');
}
If time left:
const hours = Math.floor(diff / 1000 / 60 / 60);
const mins = Math.floor((diff / 1000 / 60) % 60);
const secs = Math.floor((diff / 1000) % 60);
countdownDiv.textContent = `⌛ ${hours}h ${mins}m ${secs}s left`;
If less than 1 hour left → turns yellow:
if(diff < 3600000) countdownDiv.classList.add('warning');
This app includes:
✔ Add tasks
✔ Edit tasks
✔ Delete tasks
✔ Deadline + auto countdown
✔ Overdue detection
✔ Filters
✔ Theme Switch
✔ Save everything to LocalStorage
✔ Smooth UI with animation
Checkout My YouTube Channel
Read my other Blogs
- Top 5 Mistakes Beginners Make While Learning to Code (And How to Avoid Them)
- Best Programming Languages to Learn in 2025 (and Why)
- Before You Learn Web Development: The Advice No One Gave Me
- How to Start Coding in 2025: Beginner’s Roadmap
- Why Coding is Important: The Language of the Future
- Are Coding and Programming the Same? – The Complete Truth You Need to Know
- Will Coding Be Replaced by AI?
- C++ Programming: Everything You Need to Know
