How to Build a Kanban Board with Drag and Drop
Kanban boards are one of the most intuitive ways to visualize work in progress. From software development to content creation, teams use kanban to track tasks across stages like To Do, In Progress, and Done.
In this guide, we will build a kanban board using Next.js and the dnd-kit library. You will learn how to implement drag-and-drop between columns, manage task state, and create a responsive, interactive board.
Setting Up dnd-kit
npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilitiesBuilding the Board Component
'use client'
import { useState } from 'react'
import { DndContext, DragEndEvent, closestCorners } from '@dnd-kit/core'
const COLUMNS = [
{ id: 'todo', title: 'To Do' },
{ id: 'in-progress', title: 'In Progress' },
{ id: 'done', title: 'Done' },
]
export function KanbanBoard() {
const [tasks, setTasks] = useState([
{ id: '1', title: 'Design new homepage', column: 'todo', priority: 'high' },
{ id: '2', title: 'Implement auth flow', column: 'in-progress', priority: 'medium' },
{ id: '3', title: 'Write unit tests', column: 'todo', priority: 'low' },
{ id: '4', title: 'Deploy to production', column: 'done', priority: 'high' },
])
function handleDragEnd(event: DragEndEvent) {
const { active, over } = event
if (!over) return
const taskId = active.id as string
const overId = over.id as string
setTasks(prev => prev.map(task => {
if (task.id === taskId) {
const targetColumn = COLUMNS.find(c => c.id === overId) ? overId : task.column
return { ...task, column: targetColumn }
}
return task
}))
}
return (
<DndContext collisionDetection={closestCorners} onDragEnd={handleDragEnd}>
<div className="grid grid-cols-3 gap-4">
{COLUMNS.map(column => (
<div key={column.id} className="rounded-xl bg-gray-900 p-4">
<h3 className="text-sm font-semibold text-white mb-4">{column.title}</h3>
<div className="space-y-3">
{tasks.filter(t => t.column === column.id).map(task => (
<div key={task.id} className="rounded-lg bg-gray-800 p-3 cursor-grab">
<p className="text-sm text-white">{task.title}</p>
<span className={`mt-2 inline-block rounded px-2 py-0.5 text-xs ${
task.priority === 'high' ? 'bg-red-500/20 text-red-400' :
task.priority === 'medium' ? 'bg-yellow-500/20 text-yellow-400' :
'bg-green-500/20 text-green-400'
}`}>{task.priority}</span>
</div>
))}
</div>
</div>
))}
</div>
</DndContext>
)
}Adding Task Cards with Sortable
To make individual cards sortable within columns, wrap them with useSortable:
import { useSortable } from '@dnd-kit/sortable'
function TaskCard({ task }: { task: Task }) {
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id: task.id })
const style = transform ? {
transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
transition,
} : undefined
return (
<div ref={setNodeRef} style={style} {...attributes} {...listeners}
className="rounded-lg bg-gray-800 p-3 cursor-grab active:cursor-grabbing"
>
<p className="text-sm text-white">{task.title}</p>
</div>
)
}Cross-Selling: Ship Your Kanban Board Today
Our Kanban Board template provides a complete, production-ready drag-and-drop project management board. It includes custom columns, task cards with assignments, due dates, labels, checklists, activity logs, and team collaboration features.
Combine it with Time Tracker Pro for time logging on tasks, or Subscription Manager to turn it into a client-facing project portal. All templates work together seamlessly.
Related Template
Try this production-ready starter kit to build your project faster.
Kanban Board
Drag-and-drop project management
Ready to Build?
Get started with our production-ready starter kits and ship your project faster.
Browse Starter Kits