Back to roadmaps react Course

Project: Kanban Task Board

In this project, we will build a Kanban Task Board. Users can create new tasks, update task descriptions, and move tasks between three pipeline columns: Todo, In Progress, and Done.


1. Component State Design

We will model our tasks as an array of objects. Each task has:

  • id: A unique timestamp identifier.
  • title: The task title string.
  • status: One of "todo", "progress", or "done".

2. Implementing the Kanban Board

Create a new file named KanbanBoard.jsx and add the following implementation:

import { useState } from "react";

export function KanbanBoard() {
  const [tasks, setTasks] = useState([
    { id: 1, title: "Review pull requests", status: "todo" },
    { id: 2, title: "Configure webpack split settings", status: "progress" },
    { id: 3, title: "Setup initial git repository", status: "done" }
  ]);
  const [newTitle, setNewTitle] = useState("");

  // Create a new task item
  const addTask = (e) => {
    e.preventDefault();
    if (!newTitle.trim()) return;

    const newTask = {
      id: Date.now(),
      title: newTitle.trim(),
      status: "todo"
    };

    setTasks([...tasks, newTask]);
    setNewTitle("");
  };

  // Move task to a different status column
  const moveTask = (id, newStatus) => {
    setTasks(prevTasks =>
      prevTasks.map(task =>
        task.id === id ? { ...task, status: newStatus } : task
      )
    );
  };

  // Delete task item
  const deleteTask = (id) => {
    setTasks(prevTasks => prevTasks.filter(task => task.id !== id));
  };

  const columns = [
    { label: "To Do", value: "todo", nextStatus: "progress" },
    { label: "In Progress", value: "progress", nextStatus: "done" },
    { label: "Done", value: "done", nextStatus: null }
  ];

  return (
    <div className="kanban-wrapper">
      <form onSubmit={addTask} className="task-form">
        <input
          type="text"
          value={newTitle}
          onChange={(e) => setNewTitle(e.target.value)}
          placeholder="Enter task name..."
        />
        <button type="submit">Add Task</button>
      </form>

      <div className="kanban-grid">
        {columns.map(col => (
          <div key={col.value} className="kanban-column">
            <h2>{col.label}</h2>
            <div className="task-list">
              {tasks
                .filter(t => t.status === col.value)
                .map(task => (
                  <div key={task.id} className="task-card">
                    <p>{task.title}</p>
                    <div className="task-actions">
                      {col.nextStatus && (
                        <button onClick={() => moveTask(task.id, col.nextStatus)}>
                          Move →
                        </button>
                      )}
                      <button onClick={() => deleteTask(task.id)} className="btn-delete">
                        Delete
                      </button>
                    </div>
                  </div>
                ))}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

3. Styling the Kanban Grid

To present the columns side-by-side, use CSS Flexbox or Grid layouts:

.kanban-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  margin-top: 30px;
}

.kanban-column {
  background: #f4f5f7;
  padding: 15px;
  border-radius: 8px;
  min-height: 400px;
}

.task-card {
  background: white;
  padding: 12px;
  border-radius: 6px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
  margin-bottom: 10px;
}
Published on Last updated: