Kanban Board
A fully-featured Kanban board component with drag-and-drop, customizable cards, column WIP limits, priority indicators, assignee avatars, collapsible columns, and search filtering.
Basic Usage
A standard Kanban board with drag-and-drop, card counts, search filtering, and collapsible columns.
Basic Kanban Board
Standard board with drag-and-drop, card count, search, and collapsible columns.
import { KanbanBoard } from 'fluxo-ui';
import type { KanbanCardData, KanbanColumnData } from 'fluxo-ui';
const columns: KanbanColumnData[] = [
{ id: 'backlog', title: 'Backlog', color: '#94a3b8' },
{ id: 'todo', title: 'To Do', color: '#3b82f6' },
{ id: 'in-progress', title: 'In Progress', color: '#f59e0b', limit: 3 },
{ id: 'review', title: 'Review', color: '#8b5cf6' },
{ id: 'done', title: 'Done', color: '#10b981' },
];
const cards: KanbanCardData[] = [
{
id: '1',
title: 'Design landing page mockup',
columnId: 'backlog',
order: 0,
priority: 'medium',
labels: [{ id: 'design', text: 'Design', color: '#8b5cf6' }],
assignee: { id: 'a1', name: 'Alice Martin' },
},
// ...more cards
];
<KanbanBoard
columns={columns}
cards={cards}
draggable
showCardCount
showColumnLimit
showSearch
allowCollapse
/>Detailed Card View
Use cardSize="detailed" to show descriptions, progress bars, subtask counts, and stacked assignee avatars.
Detailed Card View
Cards with descriptions, progress bars, labels, subtask counts, and assignee stacking.
<KanbanBoard
columns={columns}
cards={cards}
cardSize="detailed"
draggable
showCardCount
showColumnLimit
allowCollapse
/>
// Card data for detailed view includes:
const card: KanbanCardData = {
id: 'd1',
title: 'Redesign dashboard',
columnId: 'todo',
order: 0,
description: 'Update all components to match new brand.',
priority: 'high',
labels: [
{ id: 'design', text: 'Design', color: '#8b5cf6' },
{ id: 'frontend', text: 'Frontend', color: '#3b82f6' },
],
assignees: [
{ id: 'a1', name: 'Alice Martin' },
{ id: 'a2', name: 'Bob Chen' },
],
dueDate: new Date('2025-04-15'),
progress: 30,
subtaskCount: 12,
subtaskCompleted: 4,
commentCount: 8,
attachmentCount: 3,
};Compact Mode
Use cardSize="compact" for a minimal card display ideal for high-density boards.
Compact Mode
Minimal card display ideal for high-density boards with many items.
<KanbanBoard
columns={columns}
cards={cards}
cardSize="compact"
draggable
showCardCount
columnWidth={240}
/>WIP Limits
Set a limit on columns to enforce work-in-progress constraints. Columns that exceed their limit display a visual warning indicator.
WIP Limits
Set limit on columns to enforce work-in-progress constraints. Columns exceeding their limit display a visual warning.
const columns: KanbanColumnData[] = [
{ id: 'todo', title: 'To Do', color: '#3b82f6' },
{ id: 'dev', title: 'Development', color: '#f59e0b', limit: 2 },
{ id: 'qa', title: 'QA', color: '#8b5cf6', limit: 2 },
{ id: 'done', title: 'Done', color: '#10b981' },
];
<KanbanBoard
columns={columns}
cards={cards}
draggable
showCardCount
showColumnLimit
/>Collapsible Columns
Enable allowCollapse to add collapse/expand toggles in column headers. Collapsed columns shrink to a narrow strip with a vertically rotated title. Set collapsed: true on a column for an initially collapsed state. Click a collapsed column to expand it.
Collapsible Columns
Click the collapse button in the column header to collapse a column. The 'Code Review' column starts collapsed. Collapsed columns display a rotated vertical title and remaining columns fill the available space. Click a collapsed column to expand it.
import { KanbanBoard } from 'fluxo-ui';
import type { KanbanColumnData, KanbanCardData, KanbanColumnId } from 'fluxo-ui';
const columns: KanbanColumnData[] = [
{ id: 'backlog', title: 'Backlog', color: '#94a3b8' },
{ id: 'todo', title: 'To Do', color: '#3b82f6' },
{ id: 'in-progress', title: 'In Progress', color: '#f59e0b' },
{ id: 'review', title: 'Code Review', color: '#8b5cf6', collapsed: true },
{ id: 'done', title: 'Done', color: '#10b981' },
];
// Set collapsed: true on a column to have it collapsed by default.
// Enable allowCollapse to show collapse/expand toggle in column headers.
// Collapsed columns shrink to ~40px with a vertically rotated title.
// Click on a collapsed column to expand it.
<KanbanBoard
columns={columns}
cards={cards}
allowCollapse
showCardCount
onColumnCollapse={(columnId, collapsed) => {
console.log(columnId, collapsed ? 'collapsed' : 'expanded');
}}
/>Blocked Cards
Set blocked: true on a card to visually indicate it is blocked. Combine with color for a colored left border.
Blocked Cards
Set blocked: true on a card to visually indicate it is blocked. Combine with color to add a colored left border.
const cards: KanbanCardData[] = [
{
id: 'b1',
title: 'Implement SSO integration',
columnId: 'in-progress',
order: 0,
priority: 'high',
blocked: true,
color: '#ef4444',
description: 'Blocked: Waiting for IdP credentials.',
},
{
id: 'b2',
title: 'Mobile push notifications',
columnId: 'in-progress',
order: 1,
priority: 'medium',
blocked: true,
},
// non-blocked cards...
];
<KanbanBoard
columns={columns}
cards={cards}
cardSize="detailed"
draggable
showCardCount
/>Locked Columns
Set locked: true on a column to prevent all interactions including drag-and-drop, editing, and adding cards.
Locked Columns
Set locked: true on a column to prevent drag-and-drop and hide add/delete controls. Ideal for archival or read-only columns.
const columns: KanbanColumnData[] = [
{ id: 'new', title: 'New', color: '#3b82f6' },
{ id: 'active', title: 'Active', color: '#f59e0b' },
{ id: 'archived', title: 'Archived', color: '#94a3b8', locked: true },
];
<KanbanBoard
columns={columns}
cards={cards}
draggable
allowAddCard
showCardCount
/>Vertical Layout
Use layout="vertical" to stack columns vertically instead of horizontally. Useful for priority triage boards or narrow containers.
Vertical Layout
Stack columns vertically instead of horizontally. Useful for priority triage or narrow containers.
<KanbanBoard
columns={columns}
cards={cards}
layout="vertical"
draggable
showCardCount
allowCollapse
/>Sticky Column Headers
Enable stickyColumnHeaders with maxColumnHeight to keep headers visible while scrolling through cards.
Sticky Column Headers
Enable stickyColumnHeaders with maxColumnHeight to keep column headers visible while scrolling through cards.
<KanbanBoard
columns={columns}
cards={cards}
draggable
showCardCount
stickyColumnHeaders
maxColumnHeight={300}
/>Custom Card Template
Use cardTemplate to render fully custom card content with any layout.
Custom Card Template
Use cardTemplate to render fully custom card content with any layout.
<KanbanBoard
columns={columns}
cards={cards}
draggable
showCardCount
columnWidth={260}
cardTemplate={(card) => (
<div className="flex items-center gap-3 p-2">
<span
className={cn('w-2 h-2 rounded-full shrink-0', {
'bg-red-500': card.priority === 'high' || card.priority === 'critical',
'bg-yellow-500': card.priority === 'medium',
'bg-green-500': card.priority === 'low',
})}
/>
<span className="text-sm font-medium truncate">
{card.title}
</span>
</div>
)}
/>Custom Column Header & Empty State
Use columnHeaderTemplate and emptyColumnTemplate for full control over column rendering.
Custom Column Header & Empty State
Use columnHeaderTemplate and emptyColumnTemplate for full control over column rendering.
<KanbanBoard
columns={columns}
cards={cards}
draggable
columnHeaderTemplate={(column, cardCount) => (
<div className="flex items-center gap-2 px-3 py-2">
<span
className="w-3 h-3 rounded-full"
style={{ backgroundColor: column.color }}
/>
<span className="text-sm font-semibold flex-1">
{column.title}
</span>
<span className="text-xs px-2 py-0.5 rounded-full bg-gray-100">
{cardCount}
</span>
</div>
)}
emptyColumnTemplate={(column) => (
<div className="text-center py-8 text-sm text-gray-400 italic">
No items in {column.title}
</div>
)}
/>Custom Card Actions
Use cardActionsTemplate to add custom action buttons in the card footer area.
Custom Card Actions
Use cardActionsTemplate to add action buttons in the card footer area.
<KanbanBoard
columns={columns}
cards={cards}
draggable
showCardCount
cardActionsTemplate={(card, column) => (
<div className="flex items-center gap-1">
<button
className="px-2 py-0.5 text-xs rounded hover:bg-gray-100"
onClick={() => console.log('Edit:', card.title)}
>
Edit
</button>
<button
className="px-2 py-0.5 text-xs rounded hover:bg-gray-100"
onClick={() => console.log('Archive:', card.title)}
>
Archive
</button>
</div>
)}
/>Interactive Board
Full interactive demo with all CRUD operations: drag cards between columns, add/delete cards and columns, edit column titles, and reorder columns.
Interactive Board
Full interactive demo: drag cards, add/delete cards and columns, edit column titles, reorder columns.
const [cards, setCards] = useState<KanbanCardData[]>(initialCards);
const [columns, setColumns] = useState<KanbanColumnData[]>(initialColumns);
<KanbanBoard
columns={columns}
cards={cards}
draggable
columnDraggable
allowAddCard
allowAddColumn
allowDeleteCard
allowDeleteColumn
allowEditColumn
allowCollapse
showCardCount
showColumnLimit
showSearch
onCardMove={(e) => {
setCards(prev => {
const without = prev.filter(c => c.id !== e.cardId);
const target = without
.filter(c => c.columnId === e.toColumnId)
.sort((a, b) => a.order - b.order);
const others = without.filter(c => c.columnId !== e.toColumnId);
const moved = { ...e.card, columnId: e.toColumnId, order: e.toIndex };
target.splice(e.toIndex, 0, moved);
return [...others, ...target.map((c, i) => ({ ...c, order: i }))];
});
}}
onCardReorder={(e) => {
setCards(prev => {
const other = prev.filter(c => c.columnId !== e.columnId);
return [...other, ...e.cards.map((c, i) => ({ ...c, order: i }))];
});
}}
onCardCreate={(e) => {
setCards(prev => [...prev, {
id: `new-${Date.now()}`,
title: e.title,
columnId: e.columnId,
order: prev.filter(c => c.columnId === e.columnId).length,
}]);
}}
onCardDelete={(e) => setCards(prev => prev.filter(c => c.id !== e.card.id))}
onColumnCreate={(e) => setColumns(prev => [...prev, { id: `col-${Date.now()}`, title: e.title }])}
onColumnDelete={(e) => {
setColumns(prev => prev.filter(c => c.id !== e.column.id));
setCards(prev => prev.filter(c => c.columnId !== e.column.id));
}}
onColumnUpdate={(e) => setColumns(prev =>
prev.map(c => c.id === e.column.id ? { ...c, [e.field]: e.value } : c)
)}
onColumnReorder={(e) => setColumns(e.columns)}
/>Import
import { KanbanBoard } from 'fluxo-ui';
// Type imports
import type {
KanbanBoardProps,
KanbanCardData,
KanbanCardId,
KanbanColumnData,
KanbanColumnId,
KanbanCardMoveEvent,
KanbanCardReorderEvent,
KanbanCardClickEvent,
KanbanCardCreateEvent,
KanbanCardDeleteEvent,
KanbanColumnCreateEvent,
KanbanColumnDeleteEvent,
KanbanColumnUpdateEvent,
KanbanColumnReorderEvent,
KanbanSearchFilter,
KanbanLabel,
KanbanAssignee,
KanbanPriority,
KanbanLayout,
KanbanCardSize,
} from 'fluxo-ui';KanbanBoard Props
columnsreqKanbanColumnData[]Array of column definitions with id, title, color, icon, limit, collapsed, locked.
columnsreqKanbanColumnData[]Array of column definitions with id, title, color, icon, limit, collapsed, locked.
cardsreqKanbanCardData[]Array of card data with id, title, columnId, order, priority, labels, assignees, etc.
cardsreqKanbanCardData[]Array of card data with id, title, columnId, order, priority, labels, assignees, etc.
layout"horizontal" | "vertical""horizontal"Board layout direction.
layout"horizontal" | "vertical""horizontal"Board layout direction.
cardSize"compact" | "default" | "detailed""default"Card display density. Compact hides labels/progress, detailed shows descriptions.
cardSize"compact" | "default" | "detailed""default"Card display density. Compact hides labels/progress, detailed shows descriptions.
classNamestringAdditional CSS class for the board container.
classNamestringAdditional CSS class for the board container.
columnWidthnumber | stringFixed column width (px or CSS value).
columnWidthnumber | stringFixed column width (px or CSS value).
columnMinHeightnumber | stringMinimum column body height.
columnMinHeightnumber | stringMinimum column body height.
maxColumnHeightnumber | stringMaximum column body scroll height.
maxColumnHeightnumber | stringMaximum column body scroll height.
draggablebooleantrueEnable drag-and-drop for cards.
draggablebooleantrueEnable drag-and-drop for cards.
columnDraggablebooleanfalseEnable drag-and-drop reordering of columns.
columnDraggablebooleanfalseEnable drag-and-drop reordering of columns.
allowAddCardbooleanfalseShow "Add card" button in each column footer.
allowAddCardbooleanfalseShow "Add card" button in each column footer.
allowAddColumnbooleanfalseShow "Add Column" button at the end.
allowAddColumnbooleanfalseShow "Add Column" button at the end.
allowDeleteCardbooleanfalseShow delete button on card hover.
allowDeleteCardbooleanfalseShow delete button on card hover.
allowDeleteColumnbooleanfalseShow delete button in column headers.
allowDeleteColumnbooleanfalseShow delete button in column headers.
allowEditColumnbooleanfalseEnable double-click to edit column title.
allowEditColumnbooleanfalseEnable double-click to edit column title.
allowCollapsebooleanfalseShow collapse/expand toggle in column headers.
allowCollapsebooleanfalseShow collapse/expand toggle in column headers.
showCardCountbooleanfalseDisplay card count badge in column headers.
showCardCountbooleanfalseDisplay card count badge in column headers.
showColumnLimitbooleanfalseDisplay WIP limit alongside card count.
showColumnLimitbooleanfalseDisplay WIP limit alongside card count.
showSearchbooleanfalseShow search input above the board.
showSearchbooleanfalseShow search input above the board.
stickyColumnHeadersbooleanfalseMake column headers sticky on scroll.
stickyColumnHeadersbooleanfalseMake column headers sticky on scroll.
cardTemplate(card, column) => ReactNodeCustom render function for card content.
cardTemplate(card, column) => ReactNodeCustom render function for card content.
columnHeaderTemplate(column, count) => ReactNodeCustom render function for column headers.
columnHeaderTemplate(column, count) => ReactNodeCustom render function for column headers.
columnFooterTemplate(column, cards) => ReactNodeCustom render function for column footers.
columnFooterTemplate(column, cards) => ReactNodeCustom render function for column footers.
emptyColumnTemplate(column) => ReactNodeCustom render function for empty columns.
emptyColumnTemplate(column) => ReactNodeCustom render function for empty columns.
cardActionsTemplate(card, column) => ReactNodeCustom actions rendered in card footer area.
cardActionsTemplate(card, column) => ReactNodeCustom actions rendered in card footer area.
onCardMove(event: KanbanCardMoveEvent) => voidCalled when a card is moved between columns.
onCardMove(event: KanbanCardMoveEvent) => voidCalled when a card is moved between columns.
onCardReorder(event: KanbanCardReorderEvent) => voidCalled when cards are reordered within a column.
onCardReorder(event: KanbanCardReorderEvent) => voidCalled when cards are reordered within a column.
onCardClick(event: KanbanCardClickEvent) => voidCalled when a card is clicked.
onCardClick(event: KanbanCardClickEvent) => voidCalled when a card is clicked.
onCardDoubleClick(event: KanbanCardClickEvent) => voidCalled when a card is double-clicked.
onCardDoubleClick(event: KanbanCardClickEvent) => voidCalled when a card is double-clicked.
onCardCreate(event: KanbanCardCreateEvent) => voidCalled when a new card is created via the add button.
onCardCreate(event: KanbanCardCreateEvent) => voidCalled when a new card is created via the add button.
onCardDelete(event: KanbanCardDeleteEvent) => voidCalled when a card delete button is clicked.
onCardDelete(event: KanbanCardDeleteEvent) => voidCalled when a card delete button is clicked.
onColumnReorder(event: KanbanColumnReorderEvent) => voidCalled when columns are reordered via drag.
onColumnReorder(event: KanbanColumnReorderEvent) => voidCalled when columns are reordered via drag.
onColumnCreate(event: KanbanColumnCreateEvent) => voidCalled when a new column is created.
onColumnCreate(event: KanbanColumnCreateEvent) => voidCalled when a new column is created.
onColumnDelete(event: KanbanColumnDeleteEvent) => voidCalled when a column is deleted.
onColumnDelete(event: KanbanColumnDeleteEvent) => voidCalled when a column is deleted.
onColumnUpdate(event: KanbanColumnUpdateEvent) => voidCalled when a column title is edited.
onColumnUpdate(event: KanbanColumnUpdateEvent) => voidCalled when a column title is edited.
onColumnCollapse(columnId, collapsed) => voidCalled when a column is collapsed or expanded.
onColumnCollapse(columnId, collapsed) => voidCalled when a column is collapsed or expanded.
onSearchChange(filter: KanbanSearchFilter) => voidCalled when the search input changes.
onSearchChange(filter: KanbanSearchFilter) => voidCalled when the search input changes.
KanbanCardData Properties
idreqstring | numberUnique identifier for the card.
idreqstring | numberUnique identifier for the card.
titlereqstringCard title displayed prominently.
titlereqstringCard title displayed prominently.
columnIdreqstring | numberID of the column this card belongs to.
columnIdreqstring | numberID of the column this card belongs to.
orderreqnumberSort position within the column.
orderreqnumberSort position within the column.
descriptionstringCard description shown in detailed view.
descriptionstringCard description shown in detailed view.
priority"critical" | "high" | "medium" | "low" | "none"Priority level with visual indicator.
priority"critical" | "high" | "medium" | "low" | "none"Priority level with visual indicator.
labelsKanbanLabel[]Color-coded labels shown on the card.
labelsKanbanLabel[]Color-coded labels shown on the card.
assigneeKanbanAssigneeSingle assignee with name and optional avatar.
assigneeKanbanAssigneeSingle assignee with name and optional avatar.
assigneesKanbanAssignee[]Multiple assignees with stacked display.
assigneesKanbanAssignee[]Multiple assignees with stacked display.
dueDateDate | stringDue date with overdue/soon indicators.
dueDateDate | stringDue date with overdue/soon indicators.
coverImagestringCover image URL shown in detailed mode.
coverImagestringCover image URL shown in detailed mode.
progressnumberCompletion percentage (0-100) shown as a progress bar.
progressnumberCompletion percentage (0-100) shown as a progress bar.
subtaskCountnumberTotal number of subtasks.
subtaskCountnumberTotal number of subtasks.
subtaskCompletednumberNumber of completed subtasks.
subtaskCompletednumberNumber of completed subtasks.
commentCountnumberNumber of comments shown as a badge.
commentCountnumberNumber of comments shown as a badge.
attachmentCountnumberNumber of attachments shown as a badge.
attachmentCountnumberNumber of attachments shown as a badge.
blockedbooleanfalseMark the card as blocked with a visual overlay.
blockedbooleanfalseMark the card as blocked with a visual overlay.
colorstringLeft border color for the card.
colorstringLeft border color for the card.
KanbanColumnData Properties
idreqstring | numberUnique identifier for the column.
idreqstring | numberUnique identifier for the column.
titlereqstringColumn header title.
titlereqstringColumn header title.
colorstringAccent color for the column header indicator.
colorstringAccent color for the column header indicator.
iconReactNodeIcon displayed next to the column title.
iconReactNodeIcon displayed next to the column title.
limitnumberMaximum number of cards (WIP limit). Visual warning when exceeded.
limitnumberMaximum number of cards (WIP limit). Visual warning when exceeded.
collapsedbooleanfalseInitial collapsed state of the column.
collapsedbooleanfalseInitial collapsed state of the column.
lockedbooleanfalsePrevent all interactions (drag, edit, add, delete).
lockedbooleanfalsePrevent all interactions (drag, edit, add, delete).
Features
Drag & Drop
Reorder cards within columns and drag cards between columns with smooth animations.
Column WIP Limits
Set work-in-progress limits per column with visual warnings when exceeded.
Priority & Labels
Visual priority indicators and customizable color-coded labels on cards.
Assignee Avatars
Show assignees with avatar images or auto-generated initials with overlap stacking.
Collapsible Columns
Collapse columns to save space with smooth transitions and vertical title display.
Search & Filter
Built-in search bar to filter cards across all columns by title or description.
Blocked Cards
Visually mark cards as blocked with a distinct overlay and optional color border.
Locked Columns
Lock columns to prevent drag-and-drop, editing, and adding cards.
Custom Templates
Full control over card, header, footer, empty state, and action rendering.
Multiple Layouts
Horizontal (default) and vertical board layouts for different use cases.
Card Sizes
Three built-in card sizes: compact, default, and detailed.
Accessibility
ARIA labels, keyboard navigation, focus-visible outlines, and semantic HTML.