Kanban Board (Drag & Drop) with HTML, CSS & JavaScript
40 DAYS 40 PROJECT CHALLENGE
Day #02
Project Overview
A modern Kanban Board is a task management web application that is built using HTML, CSS, and JavaScript. It provides a clean and responsive interface where users can organize tasks into different workflow stages, such as To Do, In Progress, and Done.
Users can create new tasks, add due dates, select priority levels, and update or delete existing tasks. Additionally, user can also drag-and-drop files and this functionality allows users to move tasks between columns easily. This project also includes a dark mode toggle and uses LocalStorage to preserve task data in the browser. This makes it a practical project for learning DOM manipulation, event handling, and frontend state management.
Key Features
- Task Creation: Users can create new tasks by entering a title, selecting a due date, and choosing a priority level. The task is added to the selected workflow column.
- Kanban Workflow: The board includes three columns: To Do, In Progress, and Done. These columns help users organize tasks according to their current progress.
- Drag-and-Drop Functionality: This project allows users to drag tasks from one column and drop them into another. JavaScript updates the task status according to the selected column.
- Task Editing: Existing tasks can be edited through a popup modal. Users can update the task title, due date, and priority without creating a new task.
- Task Deletion: Each task includes a Delete button. When clicked, the selected task is removed from the task list and LocalStorage.
- Priority Labels: Tasks can be categorized as Low, Medium, or High priority. Each priority level has a separate visual style for easier identification.
- Due Date Management: Users can assign a date to each task. If no date is selected, the task displays “No date.”
- Popup Modal: A modal form is used for adding and editing tasks. The modal includes input fields, a priority dropdown, and Save and Cancel buttons.
- LocalStorage Integration: Tasks are stored in the browser’s LocalStorage. Therefore, the saved tasks remain available after refreshing the page.
- Dark Mode Toggle: Users can switch the interface to dark mode by clicking the theme toggle button. JavaScript adds or removes the
darkclass from the body. - Responsive Layout: The board uses Flexbox and a media query to adjust the columns for smaller screens. On mobile devices, the columns appear vertically.
- Dynamic DOM Rendering: JavaScript creates task elements dynamically and updates the board whenever a task is added, edited, deleted, or moved.
What You'll Learn
- How to create a task management interface using HTML and CSS.
- How to use JavaScript DOM manipulation for dynamic content rendering.
- How to implement drag-and-drop functionality with the HTML5 Drag and Drop API.
- How to manage task data using JavaScript arrays and objects.
- How to store and retrieve data using LocalStorage.
- How to create reusable functions for adding, editing, deleting, and rendering tasks.
- How to use CSS variables for theme customization.
- How to create responsive layouts using Flexbox and media queries.
- How to handle user interactions through click, dragover, drop, and change events.
HTML Code
HTML structure creates the main layout of the Kanban Board. The page contains a header with the project title and theme toggle button. The main board includes three columns: To Do, In Progress, and Done. Each column contains an add button and an empty task list where JavaScript inserts tasks dynamically.
The modal section contains the form used to add or edit tasks. It includes a task title input, date input, priority dropdown, and action buttons. Finally, the HTML file connects the external CSS and JavaScript files to style the interface and control its functionality.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple Kanban Board</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<h1>Kanban Board</h1>
<button id="themeToggle">🌙</button>
</header>
<main class="board">
<div class="column" data-status="todo">
<div class="column-header">
<h2>To Do</h2>
<button onclick="openModal('todo')">+</button>
</div>
<div class="task-list"></div>
</div>
<div class="column" data-status="progress">
<div class="column-header">
<h2>In Progress</h2>
<button onclick="openModal('progress')">+</button>
</div>
<div class="task-list"></div>
</div>
<div class="column" data-status="done">
<div class="column-header">
<h2>Done</h2>
<button onclick="openModal('done')">+</button>
</div>
<div class="task-list"></div>
</div>
</main>
<!-- Modal -->
<div class="modal" id="modal">
<div class="modal-box">
<h3>Add Task</h3>
<input type="text" id="taskTitle" placeholder="Task title">
<input type="date" id="taskDate">
<select id="taskPriority">
<option value="low">Low Priority</option>
<option value="medium">Medium Priority</option>
<option value="high">High Priority</option>
</select>
<div class="modal-actions">
<button onclick="saveTask()">Save</button>
<button onclick="closeModal()">Cancel</button>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html> CSS Code
CSS code styles the Kanban Board using CSS variables such as --bg, --card, --text, and --border. These variables define the background, card, text, and border colors. This body.dark selector changes the card, text, and border colors when dark mode is enabled.
This .board class uses Flexbox to arrange the columns horizontally with spacing and wrapping. Each .column has a card-style design, rounded corners, padding, and a minimum width. The .task class styles individual tasks with a background, border, spacing, and a grab cursor for drag-and-drop interaction.
These .priority, .low, .medium, .high classes create different styles for task priority labels and uses fixed positioning and a semi-transparent background to appear above the page. Finally, the media query changes the board layout to a vertical column structure on screens smaller than 768 pixels.
:root{
--bg:#042354;
--card:#ffffff;
--text:#222;
--border:#e5e7eb;
}
body.dark{
--bg:#042354;
--card:#1f2937;
--text:#f3f4f6;
--border:#374151;
}
*{
margin:0;
padding:0;
box-sizing:border-box;
font-family:system-ui;
}
body{
background:var(--bg);
color:var(--text);
}
header{
display:flex;
justify-content:space-between;
align-items:center;
padding:20px;
}
header button{
border:1px solid var(--border);
background:var(--card);
padding:6px 12px;
border-radius:6px;
cursor:pointer;
}
.board{
display:flex;
gap:20px;
padding:20px;
flex-wrap:wrap;
}
.column{
background:var(--card);
border:1px solid var(--border);
border-radius:10px;
padding:15px;
flex:1;
min-width:280px;
}
.column-header{
display:flex;
justify-content:space-between;
align-items:center;
margin-bottom:15px;
}
.column-header button{
background:#6366f1;
color:white;
border:none;
width:28px;
height:28px;
border-radius:6px;
cursor:pointer;
}
.task-list{
min-height:150px;
}
.task{
background:var(--bg);
border:1px solid var(--border);
padding:10px;
border-radius:8px;
margin-bottom:10px;
cursor:grab;
}
.task strong{
font-size:14px;
color: #ffffff;
}
.task small{
display:block;
font-size:12px;
opacity:0.7;
margin-top:4px;
color: #ffffff;
}
.priority{
display:inline-block;
font-size:11px;
padding:2px 6px;
border-radius:4px;
margin-top:6px;
}
.low{
background:#d1fae5;
color:#065f46;
}
.medium{
background:#fef3c7;
color:#92400e;
}
.high{
background:#fee2e2;
color:#991b1b;
}
.task-actions{
display:flex;
gap:8px;
margin-top:8px;
}
.task-actions button{
border:none;
padding:4px 6px;
font-size:11px;
border-radius:4px;
cursor:pointer;
}
.edit-btn{
background:#6366f1;
color:white;
}
.delete-btn{
background:#ef4444;
color:white;
}
.modal{
display:none;
position:fixed;
inset:0;
background:rgba(0,0,0,0.4);
justify-content:center;
align-items:center;
}
.modal-box{
background:var(--card);
padding:20px;
border-radius:10px;
width:300px;
}
.modal-box input,
.modal-box select{
width:100%;
padding:8px;
margin-bottom:10px;
border:1px solid var(--border);
border-radius:6px;
}
.modal-actions{
display:flex;
justify-content:space-between;
}
.modal-actions button{
background:#6366f1;
color:white;
border:none;
padding:6px 12px;
border-radius:6px;
cursor:pointer;
}
@media(max-width:768px){
.board{
flex-direction:column;
}
} Javascript Code
JavaScript code manages task creation, editing, deletion, rendering, drag-and-drop movement, theme switching, and LocalStorage. First, the application retrieves previously saved tasks using localStorage.getItem() and converts the stored JSON data into a JavaScript array. The saveStorage() function saves the updated task list back to LocalStorage.
This renderTasks() function clears the existing task lists and creates task elements dynamically using document.createElement(). Each task displays its title, due date, priority, and Edit and Delete buttons. The function also adds a dragstart event to store the dragged task ID and this openModal(), closeModal() functions control the modal visibility and reset the form fields. Meanwhile, saveTask() validates the task title and either updates an existing task or creates a new task using Date.now() as its ID.
The editTask() function loads the selected task details into the modal, while deleteTask() removes the task using the filter() method. Drag-and-drop is implemented through dragover and drop events. When a task is dropped into another column, its status is updated based on the column’s data-status attribute. Finally, the theme toggle adds or removes the dark class from the body to switch the theme.
let tasks = JSON.parse(localStorage.getItem("tasks")) || [];
let currentStatus = "";
let editId = null;
function saveStorage(){
localStorage.setItem("tasks",JSON.stringify(tasks));
}
function renderTasks(){
document.querySelectorAll(".task-list").forEach(list=>list.innerHTML="");
tasks.forEach(task=>{
const div=document.createElement("div");
div.className="task";
div.draggable=true;
div.dataset.id=task.id;
div.innerHTML=`
<strong>${task.title}</strong>
<small>Due: ${task.date || "No date"}</small>
<span class="priority ${task.priority}">${task.priority}</span>
<div class="task-actions">
<button class="edit-btn" onclick="editTask(${task.id})">Edit</button>
<button class="delete-btn" onclick="deleteTask(${task.id})">Delete</button>
</div>
`;
div.addEventListener("dragstart",e=>{
e.dataTransfer.setData("text",task.id);
});
document
.querySelector(`[data-status="${task.status}"] .task-list`)
.appendChild(div);
});
saveStorage();
}
function openModal(status){
currentStatus=status;
document.getElementById("modal").style.display="flex";
}
function closeModal(){
document.getElementById("modal").style.display="none";
document.getElementById("taskTitle").value="";
document.getElementById("taskDate").value="";
editId=null;
}
function saveTask(){
const title=document.getElementById("taskTitle").value;
const date=document.getElementById("taskDate").value;
const priority=document.getElementById("taskPriority").value;
if(!title){
alert("Enter task title");
return;
}
if(editId){
const t=tasks.find(t=>t.id===editId);
t.title=title;
t.date=date;
t.priority=priority;
}else{
tasks.push({
id:Date.now(),
title,
date,
priority,
status:currentStatus
});
}
closeModal();
renderTasks();
}
function editTask(id){
const task=tasks.find(t=>t.id===id);
editId=id;
document.getElementById("taskTitle").value=task.title;
document.getElementById("taskDate").value=task.date;
document.getElementById("taskPriority").value=task.priority;
document.getElementById("modal").style.display="flex";
}
function deleteTask(id){
tasks=tasks.filter(t=>t.id!==id);
renderTasks();
}
document.querySelectorAll(".task-list").forEach(list=>{
list.addEventListener("dragover",e=>e.preventDefault());
list.addEventListener("drop",e=>{
e.preventDefault();
const id=e.dataTransfer.getData("text");
const task=tasks.find(t=>t.id==id);
task.status=list.closest(".column").dataset.status;
renderTasks();
});
});
document.getElementById("themeToggle").addEventListener("click",()=>{
document.body.classList.toggle("dark");
});
renderTasks(); Related Projects
Day 4 : Invoice Generator
Creates invoices dynamically with item details and real-time total calculation.
Concepts: DOM manipulation, form handling, calculations, data rendering.
Day 5 : Chat UI (Frontend Only)
A simple chat interface with message sending and display functionality.
Concepts: DOM manipulation, event handling, dynamic UI updates.
Day 6 : File Upload Progress Bar
File upload interface with a visual progress bar and smooth animation.
Concepts: File API, progress tracking, animations, event handling.