Open In App

Build A Drag & Drop Kanban Board using HTML CSS & JavaScript

Last Updated : 13 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

A Kanban board is a project management tool designed to visualize work, limit work in progress, and maximize efficiency. With drag & drop functionality, users can easily move tasks between different stages of completion, providing a visual representation of the workflow.

ss1

Final Output

Approach:

The below defined steps can be utilised to build and design a Kanban board layout:

  • In the first step, we will create a folder with the project name and create the HTML, CSS, JavaScript files.
  • Now, use the different HTML tags like header, meta, title, head, div, input, img logo etc to structure the web page.
  • Style the different components and the elements of HTML responsively to make the page attractive for every device using CSS.
  • To define the responsive styles, Adjust the width of the containers in %.
  • Use JavaScript to add interactivity, including drag and drop functionality.
  • Add functionality to allow users to add, edit, and delete tasks.

Example: This example describes the basic implementation of the Drag & Drop Kanban Board using HTML, CSS, and JavaScript.

HTML
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content=
"width=device-width, initial-scale=1.0">
    <title>Kanban Board</title>
    <link rel="stylesheet" href="style.css">
    <link rel="stylesheet" href=
"https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap">
</head>

<body>
    <div class="head">
        <img src=
"https://media.geeksforgeeks.org/gfg-gg-logo.svg">
        <h1>Kanban Board</h1>
    </div>
    <div class="board">
        <div class="column" id="todo" ondrop="drop(event, 'todo')" 
            ondragover="allowDrop(event)">
            <h2>Todo</h2>
            <hr>
            <div class="tasks-in-btn">
                <input type="text" id="taskInput" class="task-input" 
                    placeholder="Enter a task..."
                    oninput="capitalizeInput(this)">
                <button class="add-task-btn" onclick="addTask('todo')">
                    Add Task
                </button>
            </div>
            <div class="task-container"></div>
        </div>

        <div class="column" id="in-progress" 
            ondrop="drop(event, 'in-progress')" 
            ondragover="allowDrop(event)">
            <h2>In Progress</h2>
            <hr>
            <div class="task-container"></div>
        </div>
        <div class="column" id="done" 
            ondrop="drop(event, 'done')" 
            ondragover="allowDrop(event)">
            <h2>Done</h2>
            <hr>
            <div class="task-container"></div>
        </div>
    </div>

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

</html>
CSS
/* style.css */
body {
    font-family: 'Roboto', sans-serif;
    background-color: #f5f5f5;
    margin: 0;
    padding: 0;
}

.head {
    background-color: #1976d2;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    box-shadow:
        0px 2px 5px rgba(0, 0, 0, 0.1);
}

.head img {
    width: 50px;
    margin-right: 10px;
}

.head h1 {
    font-size: 24px;
    margin: 0;
}

.board {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-around;
    padding: 20px;
}

.column {
    /* width: 30%; */
    width: calc(100% - 30px);
    max-width: 400px;
    margin: 10px;
    background-color: #fff;
    border-radius: 10px;
    padding: 20px;
    box-shadow:
        0px 2px 5px rgba(0, 0, 0, 0.1);
}

.column h2 {
    font-size: 18px;
    margin-bottom: 10px;
    color: #333;
}

.task-input {
    width: 60%;
    padding: 8px;
    border: 1px solid #ccc;
    border-radius: 5px;
    margin-bottom: 10px;
}

.task {
    background-color: #e0e0e0;
    padding: 10px;
    border-radius: 5px;
    margin-bottom: 10px;
    cursor: move;
}

.delete-btn {
    float: right;
    cursor: pointer;
}

.add-task-btn {
    background-color: #4caf50;
    border: none;
    color: white;
    /* Adjust padding to make 
    the button smaller */
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 14px;
    /* Decrease font size */
    border-radius: 5px;
    /* Adjust border radius 
    for a softer look */
    cursor: pointer;
    transition: background-color 0.3s;
}


.add-task-btn:hover {
    background-color: #45a049;
}


#todo .task {
    background-color: #b3e5fc;
    /* Light blue */
}

#in-progress .task {
    background-color: #ffcdd2;
    /* Light pink */
}

#done .task {
    background-color: #c8e6c9;
    /* Light green */
}

.task {
    display: flex;
    align-items: center;
    justify-content: space-between;
    border: 1px solid #ccc;
    border-radius: 5px;
    padding: 5px;
    margin-bottom: 5px;
    cursor: move;
}

.delete-btn {
    float: right;

    cursor: pointer;
}

.tasks-in-btn {
    display: flex;
    justify-content: space-around;
    margin-bottom: 3px;

}
Javascript
//script.js
let tasks = JSON.parse
    (localStorage.getItem('tasks')) || [];

document.addEventListener
    ("DOMContentLoaded", function () {
        renderTasks();
    });

// Function to render tasks on the board
function renderTasks() {
    const columns =
        ['todo', 'in-progress', 'done'];

    columns.forEach(columnId => {
        const column =
            document.getElementById(columnId);
        column.querySelector('.task-container').
            innerHTML = '';

        tasks.forEach(task => {
            if (task.status === columnId) {
                const taskElement =
                    createTaskElement(task.content, task.id);
                column.querySelector('.task-container').
                    appendChild(taskElement);
            }
        });
    });
}

function createTaskElement(content, id) {
    const taskId = id
    const task = document.createElement("div");
    task.id = taskId;
    task.className = "task";
    task.draggable = true;
    task.innerHTML =
        `${content}
    <span class="delete-btn" 
        onclick="deleteTask('${taskId}')">
        
    </span>`;
    task.addEventListener("dragstart", drag);
    return task;
}


// Function to delete a task
function deleteTask(taskId) {
    tasks = tasks.
        filter(task => task.id !== taskId);
    updateLocalStorage();
    renderTasks();
}

function allowDrop(event) {
    event.preventDefault();
}

function drag(event) {
    event.dataTransfer.
        setData("text/plain", event.target.id);
}

function drop(event, columnId) {
    event.preventDefault();
    console.log(columnId)
    const data = event.
        dataTransfer.getData("text/plain");
    const draggedElement =
        document.getElementById(data);
    console.log(draggedElement)
    if (draggedElement) {
        const taskStatus = columnId;
        updateTaskStatus(data, taskStatus);
        event.target.querySelector('.task-container').
            appendChild(draggedElement);
    }
}

function capitalizeInput(input) {
    input.value = input.value.toUpperCase();
}

function addTask(columnId) {
    const taskInput =
        document.getElementById('taskInput');
    const taskContent = taskInput.value.trim();
    if (taskContent !== "") {
        const newTask = {
            id: "task-" + Date.now(),
            content: taskContent,
            status: columnId
        };
        tasks.push(newTask);
        updateLocalStorage();
        renderTasks();
        taskInput.value = "";
    }
}

// Function to update task status 
// when moved to another column
function updateTaskStatus(taskId, newStatus) {
    console.log(newStatus)
    tasks = tasks.map(task => {
        console.log(task)
        console.log(taskId)
        if (task.id === taskId) {
            console.log("inside if")
            return { ...task, status: newStatus };
        }
        return task;
    });
    updateLocalStorage();
}

// Function to update local 
// storage with current tasks
function updateLocalStorage() {
    console.log("task update")
    localStorage.setItem
        ('tasks', JSON.stringify(tasks));
}

Output:

output

final output gif



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads