# Kanban board

A React component in [Beamline](https://beamline.io/)'s [Data & tables](https://beamline.io/components/data) category. Live demo: https://beamline.io/components/kanban-board

Work as cards in columns by stage: drag a card (or lift it with Space and walk it with the arrows) to another column or place, the cards around it make room as it travels; columns keep work-in-progress limits that warn or refuse, fold into a narrow rail, and swipe one by one in a narrow room.

## Use it for

- Work items that move through stages: issues in a sprint, deals in a pipeline, candidates in hiring, content in review.
- A team needs to see where work piles up (work-in-progress limits per column) and move items by hand.

## Not for

- Hundreds of records to sort and filter ([data-grid](https://beamline.io/components/data-grid)).
- Work that is mostly about dates and durations ([gantt-chart](https://beamline.io/components/gantt-chart), [event-calendar](https://beamline.io/components/event-calendar)).
- An agent's own steps with live status (plan or [task-rows](https://beamline.io/components/task-rows)).

## Anatomy

- root (a size container; scrolls columns sideways when they outgrow it)
- column: header (icon, title, count, limit “3 / 5”, over-limit word and glyph, fold and add buttons), list of cards, empty drop area, footer Add card
- folded column: a narrow rail with the title written down it and the count
- card: key, priority glyph, title, labels, due date, sub-task progress, estimate, assignees (or your own renderCard)
- drop slot (where the dragged card will land) and the lifted card that follows the pointer
- live region announcing lift, every move and the drop

## Variants

- **0**: density: compact · default · comfortable (comfortable shows the description)
- **1**: limitMode: warn (a column over its limit says so) · strict (a full column refuses a card)
- **2**: renderCard for a card of your own; the board keeps drag, keyboard and motion

## States

- loading (skeleton cards in each column)
- empty column (a dashed area that says what goes there; “Drop here” while dragging)
- dragging (slot open where the card would land; others make room)
- lifted by keyboard (the card itself moves; a ring and raised paint mark it)
- refused (the target column says why: its limit, or the reason canMove returned)
- over limit (warning tone, glyph and the words “Over limit”)
- at limit (count reads 5 / 5 in ink)
- folded column
- estimate not set (hatched, never 0)

## Keyboard

- Tab reaches the board's cards as one stop (the last one used), then each column's buttons
- ↑ ↓ move between cards in a column; ← → to the neighbouring column's card at the same height
- Home / End: first / last card of the column
- Space lifts the focused card; then ↑ ↓ move it within the column, ← → to the next column; Space or Enter drops it; Escape puts it back
- Enter opens the card (onCardOpen) when not lifted
- Folding or opening a column keeps focus on its replacement control; folded cards cannot take the board’s single card tab stop.

## Motion

A card under the pointer lifts at once (raised paint, a slight tilt and swell) and follows the finger; the slot it would land in opens where it is and the cards around it slide to make room (useFlip). On release the card flies into its slot on the held spring (the one sanctioned bounce: an object the hand let go of). A keyboard-lifted card itself slides from place to place. Cards added or moved by someone else slide or grow in; removed ones leave a fading ghost. A column folds into its rail and opens again by its width. Under reduced motion every change is placed at once; nothing runs at rest.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `columns` (required) | `KanbanColumn[]` | — | { id, title, limit?, icon?, tone?, description? } in board order. |
| `value / defaultValue / onValueChange` | `KanbanCard[] / (cards, move) => void` | — | Every card with its column; order within a column is array order. onValueChange receives the new array and the move { card, from, to, index }. |
| `canMove` | `(card, to: string, index: number) => true \| string` | — | Return a reason to refuse a move ("Needs a reviewer first"); the target column shows it and the card goes back. |
| `limitMode` | `"warn" \| "strict"` | — | warn (default): a column over its limit says so. strict: a full column refuses another card. |
| `onCardOpen` | `(card) => void` | — | Click or Enter on a card (not after a drag). |
| `onAddCard` | `(columnId) => void` | — | Shows Add card at the end of each column. |
| `collapsed / defaultCollapsed / onCollapsedChange` | `string[]` | — | Columns folded into a narrow rail. |
| `renderCard` | `(card, state: { lifted }) => ReactNode` | — | Your own card body; the board keeps the frame, drag and keyboard. |
| `density` | `"compact" \| "default" \| "comfortable"` | — | Card padding; comfortable also shows the description. |
| `loading` | `boolean` | — | Skeleton cards in every column; the columns keep their place. |
| `emptyLabel` | `string` | — | What an empty column says. Default "No cards". |
| `aria-label` (required) | `string` | — | The board's name: "Sprint 42". |
| `className / classNames / style / ref` | `string / KanbanClassNames / CSSProperties / Ref<HTMLDivElement>` | — | The root and its documented parts (column, header, list, card, slot, rail). |

## Dependencies

`motion`, `lucide-react`

## Import

```tsx
import { KanbanBoard } from "@/components/kanban-board/kanban-board";
```

## Get it

Kanban board is part of Beamline: 200+ components and 50+ complete screens for React that your coding agent (Claude Code, Codex, Cursor or any MCP client) installs into your app through Beamline's MCP server, as a ready-built package or as plain React source you can change. $49 launch price, one payment, no subscription, lifetime updates, one licence for your whole team. [Get Beamline](https://beamline.io/checkout?pack=complete) · [Connect your agent](https://beamline.io/connect)

## More in Data & tables

- [Event calendar](https://beamline.io/components/event-calendar): A schedule of events by day, week or month: events that overlap sit side by side, drag one to another time or day or pull its bottom edge to change its…
- [Data grid](https://beamline.io/components/data-grid): Virtualised grid for thousands of rows: multi-sort, search and value filters, resizable and pinnable columns, range selection, inline edit, footer…
- [Pivot table](https://beamline.io/components/pivot-table): Records summed up by the fields people choose: rows grouped by one or more fields that fold open level by level, columns split by another, one or more…
- [Query builder](https://beamline.io/components/query-builder): Conditions people build by hand to pick out records: each rule is a field, an operator that fits the field (contains, between, in the last N days, is any…
- [Log viewer](https://beamline.io/components/log-viewer): Log lines as they stream: it follows the newest line until you scroll up, then counts what arrived and brings you back in one click; filter by level with…
- [JSON viewer](https://beamline.io/components/json-viewer): A JSON value as a tree you can read and walk: branches open and close (one level, or all at once), closed ones preview what they hold, every value reads…
- [JSON diff viewer](https://beamline.io/components/json-diff-viewer): Two versions of a JSON value compared as one tree: added keys marked +, removed ones struck through with −, changed values read old → new, unchanged keys…
- [Import mapping](https://beamline.io/components/import-mapping): Map the columns of a file to the fields of one record type, see what every value becomes, then run the import and get an outcome for each row…
- [Diff table](https://beamline.io/components/diff-table): Proposed edits to a table before they happen: new rows green, removals struck through, changed cells old → new; each change can be left out and Apply…
- [Filter toolbar](https://beamline.io/components/filter-toolbar): The filters on a list kept in view: chips that remove themselves, Add filter with fields and their values, Clear all, and room for search or view controls.
- [Table](https://beamline.io/components/table): A plain, styled HTML table for small static data: header, body, footer, caption, numeric cells, three densities and a sticky header.
