Posted in

How to Build an Advanced To-Do App with Deadlines, Countdown Timers, and Dark Mode (Step-by-Step Guide)

TODO LIST APP

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

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:

FeaturePurpose
Header + theme buttonSwitch between light and dark modes
Task inputEnter new tasks
Deadline inputSet due date/time
Add buttonAdd tasks dynamically
FiltersShow only specific tasks
Task listDisplay tasks created by JS
Clear allQuickly remove everything

CSS File Explanation (Line-by-Line / Section-by-Section)

Your CSS contains:

  1. Google Font
  2. Theme variables
  3. Reset
  4. Layout (body, containers)
  5. Theme Dark Mode support
  6. Input styling
  7. Filter styling
  8. Task list styling
  9. Buttons
  10. Animations
  11. 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 box
  • deadlineInput → the deadline input
  • addBtn → the Add button
  • taskList → the <ul> where tasks will appear
  • filters → 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:

  1. loadTasks() → gets saved tasks from localStorage
  2. loadTheme() → loads saved light/dark theme
  3. 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:

  1. Reads text & deadline
  2. Validates them
  3. Creates a list item (<li>) using createTaskElement()
  4. Adds it to the task list
  5. Saves to localStorage
  6. 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

  1. Top 5 Mistakes Beginners Make While Learning to Code (And How to Avoid Them)
  2. Best Programming Languages to Learn in 2025 (and Why)
  3. Before You Learn Web Development: The Advice No One Gave Me
  4. How to Start Coding in 2025: Beginner’s Roadmap
  5. Why Coding is Important: The Language of the Future
  6. Are Coding and Programming the Same? – The Complete Truth You Need to Know
  7. Will Coding Be Replaced by AI?
  8. C++ Programming: Everything You Need to Know

I’m Shaurya, a developer simplifying tech with tutorials, tools, and projects to help you learn, build, and grow in the world of coding.

Leave a Reply

Your email address will not be published. Required fields are marked *