KanbanBoard
A drag-and-drop Kanban board with keyboard support. Cards can be dragged between columns and reordered within columns. The card face (what gets dragged) ships a default template but can be fully replaced via renderCard. KanbanCard ships no built-in edit form: the details popup is entirely bring-your-own. Pass a renderCardDetails function to render whatever content you want inside the Modal that opens on click; omit it and the board is drag-only, no popup, no info button.
Installation
npx dafink-ui add kanbanAlso installs: Modal
Requires: @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/utilities
Demos
To Do
2Research competitors
Write spec
Define requirements for v2.
In Progress
2Build prototype
Design review
Review mockups with the team.
Done
1Kick-off meeting
Align on goals and timeline.
Custom card face
KanbanCard ships a default face (tag, title, description, meta row), but renderCard replaces it entirely — the outer draggable wrapper, click-to-open, and keyboard support all keep working. This one swaps in a compact row: a tag-colored dot, the title, and a chevron that calls onViewDetails to open the (equally custom) details popup.
Backlog
2Active
1Shipped
1Composition
Props
| Name | Type | Default | Description |
|---|---|---|---|
| initialColumns | KanbanColumnData[] | - | Initial column and card data. Column and card state is managed internally. |
| onCardUpdate | (card: KanbanCardData) => void | - | Fired after a card is edited and saved in its details popup, with the updated card. |
| onCardDelete | (id: string) => void | - | Fired after a card is deleted from its details popup, with the id of the deleted card. |
| renderCardDetails | (props: { card, onUpdate, onDelete, onClose }) => ReactNode | - | Renders the content of the details Modal opened when a card is clicked. There is no built-in form — this is entirely bring-your-own. Omit it to disable the popup entirely: cards become drag-only, with no info button and no click behavior. |
| renderCard | (props: { card, isDragging, onViewDetails }) => ReactNode | - | Renders the card face shown on the board and dragged. Omit it to use the default template (tag, title, description, points/due-date/subtasks meta row, and an info button when renderCardDetails is set). A custom face can call onViewDetails to open the details popup itself. |
| className | string | "" | Extra classes on the board container. |
Accessibility
KanbanBoard uses dnd-kit's KeyboardSensor (sortableKeyboardCoordinates) alongside its pointer sensor, so every card is genuinely keyboard-draggable: KanbanCard's root element is the same one carrying useSortable's attributes/listeners, giving it role="button", tabIndex=0, and an aria-label instructing how to start a drag — there's no separate grip handle and no roving tabindex; cards just sit in normal tab order. When renderCardDetails is provided, viewing details moves to an independently focusable info button (Space/Enter on the card itself stay claimed for dragging), and the details Modal it opens follows the standard focus-trap / Escape-closes / return-focus-to-trigger overlay contract.
| Key | Function |
|---|---|
| tab | Moves focus to the next card (or its info button, if present), following normal document order. |
| space | Starts dragging the focused card; press again to drop it at its current position. |
| enter | Starts dragging the focused card; press again to drop it at its current position. |
| up arrow | While dragging, moves the card up within or across columns. |
| down arrow | While dragging, moves the card down within or across columns. |
| left arrow | While dragging, moves the card toward the previous column. |
| right arrow | While dragging, moves the card toward the next column. |
| escape | Cancels an in-progress drag, returning the card to its original position. |