đź“‹Building a To-Do List with a Date Picker đź“… using HTML, CSS, and JavaScript
July 01, 20255 min read

đź“‹Building a To-Do List with a Date Picker đź“… using HTML, CSS, and JavaScript

Web developmentJavaScriptCSS3JavaScript Projects
share this article on

A to-do list is a simple yet effective tool to manage daily tasks efficiently. In this tutorial, we will create a to-do list with a date picker using HTML, CSS, and JavaScript

✨ Features of the to-do List app

  1. Adding tasks with a due date.
  2. Storing tasks in local storage for persistence.
  3. Displaying tasks with a countdown of days left.
  4. Marking tasks as completed.
  5. Showing overdue tasks.
  6. Deleting individual tasks or clearing all tasks at once.

đź§± Project Structure

/to-do-list-app
  ├── index.html
  ├── styles.css
  └── script.js

🖼️ HTML Code: to-do list app

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>To-Do List</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <div class="container">
    <h1>To-Do List</h1>
    <div class="input-container">
      <input type="text" id="task-input" placeholder="Enter your task...">
      <div class="date-picker">
        <span class="calendar-icon" id="calendar-icon">đź“…</span>
        <input type="date" id="task-date" class="hidden" />
      </div>
      <button id="add-task-btn">+</button>
    </div>

    <div id="task-list"></div>

    <!-- Bottom section for pending tasks and clear all button -->
    <div id="footer">
      <p id="pending-tasks">You have 0 pending tasks.</p>
      <button id="clear-all-btn" style="display: none;">Clear All</button>
    </div>
  </div>

  <script src="script.js"></script>
</body>
</html>

Explanation:

🎨 CSS Code: Styling for to-do list app

:root {
    --gradient: linear-gradient(130deg, #ef893b, #e75c2c);
    --gradient-hover: linear-gradient(90deg, #e75c2c, #ef893b);
}

body {
    font-family: Arial, sans-serif;
    background-image: var(--gradient);
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
}

.container {
    width: 550px;
    padding: 20px;
    background: #2c3036;
    border-radius: 10px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
    text-align: center;
}

h1 {
    margin-bottom: 20px;
    color: #898f97;
}

.input-container {
    display: flex;
    justify-content: center;
    margin-bottom: 20px;
    align-items: center;
    gap: 10px;
}

input {
    padding: 10px;
    border-radius: 5px;
    background-color: #363a41;
    font-size: 16px;
}

input[type=text] {
    flex-grow: 1;
    padding: 10px;
    border-radius: 5px;
    background-color: #363a41;
    font-size: 16px;
    color: #f6f6f6;
}

input:focus {
    outline: none;
}

input.edit-date {
    background-color: #ccc;
}

button {
    padding: 10px 14px;
    border: none;
    background: var(--gradient);
    color: white;
    font-size: 20px;
    cursor: pointer;
    font-weight: 600;
    border-radius: 5px;
}

button:hover {
    background: var(--gradient-hover);
}

ul {
    list-style: none;
    padding: 0;
}

li {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background: #131827;
    padding: 10px;
    margin: 5px 0;
    border-radius: 5px;
}

li span {
    flex: 1;
    color: #898f97;
    margin-left: 10px;
    text-align: left;
}

.task-checkbox {
    appearance: none;
    width: 16px;
    height: 16px;
    border: 2px solid #898f97;
    border-radius: 50%;
    cursor: pointer;
    position: relative;
}

.task-checkbox:checked {
    background-color: #28a745;
    border-color: #28a745;
}

.task-checkbox:checked::after {
    content: 'âś”';
    color: white;
    font-size: 14px;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

.delete-btn {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 18px;
    color: red;
}

.delete-btn:hover {
    color: darkred;
    background: none;
}

.edit-btn, .edit-btn:hover,
.save-btn, .save-btn:hover
{
    background: none;
}

.completed {    
    text-decoration: line-through;
    color: gray;
}

.task-checkbox {
    margin-right: 10px;
    cursor: pointer;
}

#pending-tasks {
    margin-top: 15px;
    font-size: 16px;
    color: #898f97;
    font-weight: bold;
    text-align: center;
}

.hidden {
    position: absolute;
    opacity: 0;
    pointer-events: none
}

.days-left {
    font-size: 14px;
    color: #ff5733;
}

#footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 15px;
    font-size: 16px;
    color: #333;
    font-weight: bold;
}

#clear-all-btn {
    padding: 8px 12px;
    background: red;
    color: white;
    border: none;
    cursor: pointer;
    font-size: 14px;
    border-radius: 5px;
    display: none;
}

#clear-all-btn:hover {
    background: darkred;
}


.date-picker {
    position: relative;
    width: 40px;
    height: 40px;
    background: #363a41;
    border-radius: 5px;
    cursor: pointer;
    display: inline-block; 
    text-align: center;
}

.calendar-icon {
    font-size: 20px;
    color: white;
    cursor: pointer;
    line-height: 40px;
}

Explanation:

đź§  JavaScript Functionality

document.addEventListener("DOMContentLoaded", loadTasks);

const taskInput = document.getElementById("task-input");
const taskDateInput = document.getElementById("task-date");
const calendarIcon = document.getElementById("calendar-icon");
const addTaskBtn = document.getElementById("add-task-btn");
const taskList = document.getElementById("task-list");
const pendingTaskCount = document.getElementById("pending-tasks");
const clearAllBtn = document.getElementById("clear-all-btn");

let selectedDate = "";

// Show date picker when clicking the calendar icon
calendarIcon.addEventListener("click", () => taskDateInput.showPicker());

// Capture selected date
taskDateInput.addEventListener("change", (e) => {
  selectedDate = e.target.value;
});

addTaskBtn.addEventListener("click", addTask);
clearAllBtn.addEventListener("click", clearAllTasks);

function addTask() {
  const taskText = taskInput.value.trim();
  if (taskText === "" || selectedDate === "") {
    alert("Please enter a task and select a due date.");
    return;
  }

  const taskItem = createTaskElement(taskText, false, selectedDate);
  taskList.appendChild(taskItem);
  saveTaskToLocalStorage(taskText, false, selectedDate);
  taskInput.value = "";
  selectedDate = "";

  updatePendingTasks();
}

function createTaskElement(taskText, isCompleted, taskDate) {
  const li = document.createElement("li");
  const daysLeft = calculateDaysLeft(taskDate);
  const daysLeftText = daysLeft === 0 ? "Task Overdue" : `${daysLeft} ${daysLeft === 1 ? "day" : "days"} left`;

  let color = daysLeft < 3 ? "red" : daysLeft <= 5 ? "orange" : "green";

  li.innerHTML = `
    <input type="checkbox" class="task-checkbox" ${isCompleted ? "checked" : ""}>
    <span class="task-text ${isCompleted ? "completed" : ""}">${taskText}</span>
    <span class="days-left" style="color: ${color};">${daysLeftText}</span>
    <button class="edit-btn">✏️</button>
    <button class="delete-btn">❌</button>
  `;

  const editBtn = li.querySelector(".edit-btn");
  const deleteBtn = li.querySelector(".delete-btn");
  const taskTextElement = li.querySelector(".task-text");

  li.querySelector(".task-checkbox").addEventListener("change", (e) => {
    const isChecked = e.target.checked;
    taskTextElement.classList.toggle("completed", isChecked);
    updateTaskStatus(taskText, isChecked, taskDate);
    updatePendingTasks();
  });

  editBtn.addEventListener("click", () => editTask(li, taskText, taskDate));
  deleteBtn.addEventListener("click", () => {
    removeTaskFromLocalStorage(taskText);
    li.remove();
    updatePendingTasks();
  });

  return li;
}

function editTask(li, oldText, oldDate) {
  const taskTextElement = li.querySelector(".task-text");
  const daysLeftElement = li.querySelector(".days-left");
  const editBtn = li.querySelector(".edit-btn");

  // Create an input field for editing the task text
  const textInput = document.createElement("input");
  textInput.type = "text";
  textInput.value = taskTextElement.textContent;
  textInput.classList.add("edit-input");

  // Create a date picker for editing the due date
  const dateInput = document.createElement("input");
  dateInput.type = "date";
  dateInput.value = oldDate;
  dateInput.classList.add("edit-date");

  // Create a save button
  const saveBtn = document.createElement("button");
  saveBtn.innerHTML = "đź’ľ";
  saveBtn.classList.add("save-btn");

  // Replace elements with input fields
  li.replaceChild(textInput, taskTextElement);
  li.replaceChild(dateInput, daysLeftElement);
  li.replaceChild(saveBtn, editBtn);

  saveBtn.addEventListener("click", () => saveEditedTask(li, oldText, textInput.value, dateInput.value));
}

function saveEditedTask(li, oldText, newText, newDate) {
  if (!newText.trim() || !newDate) {
    alert("Task name and date cannot be empty.");
    return;
  }

  const daysLeft = calculateDaysLeft(newDate);
  const daysLeftText = daysLeft === 0 ? "Task Overdue" : `${daysLeft} ${daysLeft === 1 ? "day" : "days"} left`;
  let color = daysLeft < 3 ? "red" : daysLeft <= 5 ? "orange" : "green";

  // Restore task text and days left elements
  const taskTextElement = document.createElement("span");
  taskTextElement.textContent = newText;
  taskTextElement.classList.add("task-text");

  const daysLeftElement = document.createElement("span");
  daysLeftElement.textContent = daysLeftText;
  daysLeftElement.style.color = color;
  daysLeftElement.classList.add("days-left");

  const editBtn = document.createElement("button");
  editBtn.innerHTML = "✏️";
  editBtn.classList.add("edit-btn");

  // Restore elements in the list item
  li.replaceChild(taskTextElement, li.querySelector(".edit-input"));
  li.replaceChild(daysLeftElement, li.querySelector(".edit-date"));
  li.replaceChild(editBtn, li.querySelector(".save-btn"));

  editBtn.addEventListener("click", () => editTask(li, newText, newDate));

  updateTaskInLocalStorage(oldText, newText, newDate);
  loadTasks(); // Reload sorted tasks
}

function calculateDaysLeft(taskDate) {
  const today = new Date();
  const dueDate = new Date(taskDate);
  const timeDiff = dueDate - today;
  const daysLeft = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
  return daysLeft < 0 ? 0 : daysLeft;
}

function saveTaskToLocalStorage(taskText, isCompleted, taskDate) {
  let tasks = JSON.parse(localStorage.getItem("tasks")) || [];
  tasks.push({ text: taskText, completed: isCompleted, date: taskDate });
  localStorage.setItem("tasks", JSON.stringify(tasks));
}

function updateTaskInLocalStorage(oldText, newText, newDate) {
  let tasks = JSON.parse(localStorage.getItem("tasks")) || [];
  tasks = tasks.map(task => 
    task.text === oldText ? { text: newText, completed: task.completed, date: newDate } : task
  );
  localStorage.setItem("tasks", JSON.stringify(tasks));
}

function removeTaskFromLocalStorage(taskText) {
  let tasks = JSON.parse(localStorage.getItem("tasks")) || [];
  tasks = tasks.filter(task => task.text !== taskText);
  localStorage.setItem("tasks", JSON.stringify(tasks));
}

function loadTasks() {
  let tasks = JSON.parse(localStorage.getItem("tasks")) || [];

  
  tasks.sort((a, b) => calculateDaysLeft(a.date) - calculateDaysLeft(b.date));

  taskList.innerHTML = "";
  tasks.forEach(task => {
    const taskItem = createTaskElement(task.text, task.completed, task.date);
    taskList.appendChild(taskItem);
  });

  updatePendingTasks();
}

function updatePendingTasks() {
  let tasks = JSON.parse(localStorage.getItem("tasks")) || [];
  let pendingCount = tasks.filter(task => !task.completed).length;
  pendingTaskCount.textContent = `You have ${pendingCount} pending tasks.`;
  clearAllBtn.style.display = tasks.length > 0 ? "inline-block" : "none";
}

clearAllBtn.addEventListener("click", clearAllTasks);

function clearAllTasks() {
  localStorage.removeItem("tasks"); // Clear tasks from local storage
  taskList.innerHTML = ""; // Clear all tasks from the DOM
  updatePendingTasks(); // Update the pending tasks count
}

Explanation:

Conclusion

This to-do list effectively manages tasks with due dates, highlights overdue tasks, and persists data using local storage. Try customizing it further to enhance its functionality!

Happy coding!


Back to Articles