List Kanban

Ideas

3
  • LisbonNov 2Coliseu dos RecreiosAsk Arooj Aftab to open
  • OsloNov 9Sentralen
  • KyotoDec 1Taku TakuAcoustic set only

Booked

2
  • ReykjavíkOct 12HarpaSupport: Ólafur Arnalds
  • BerlinOct 18Funkhaus

On the road

3 / 3
  • LondonOct 3BarbicanStrings with Hania Rani
  • ParisOct 5La Cigale
  • BrusselsOct 7Ancienne Belgique

Done

1
  • GlasgowSep 28BarrowlandSold out, record the encore

Press Space or Enter to pick up a card. Use the up and down arrows to move it within a column, left and right to move it between columns, Space or Enter to drop it, and Escape to cancel.

About this component

List Kanban

A kanban board: cards dragged within and between columns. The card lifts into a floating ghost that tilts slightly and follows the pointer, a dashed slot shows where it will land while the other cards make room on a spring; on drop the card settles from the ghost into its slot. The board scrolls sideways near its edges and tall columns scroll on their own. On touch a short long press lifts a card, so the board still scrolls under a passing finger. The keyboard does it all too: Space picks a card up, the up and down arrows move it within a column, left and right carry it between columns, Space drops it and Escape puts it back, with every step announced. Columns take a color dot and a work-in-progress limit that tints the header when exceeded. Controlled or uncontrolled, any card shape, your own card content.

Usage

The import and the props worth knowing about, in one place.

import { ListKanban, type KanbanColumn } from "@/components/beste/component/list-kanban";

type Task = { id: string; title: string };

const [columns, setColumns] = useState<KanbanColumn<Task>[]>([
  { id: "todo", title: "To do", color: "#a1a1aa", cards: [{ id: "t1", title: "Mix the live album" }] },
  { id: "doing", title: "Doing", color: "#f59e0b", limit: 2, cards: [] },
  { id: "done", title: "Done", color: "#10b981", cards: [] },
]);

<ListKanban
  columns={columns}
  onChange={(next, move) => {
    setColumns(next);
    console.log("moved", move.card.title, "to", move.to.column);
  }}
  getCardLabel={(task) => task.title}
  renderCard={(task) => <span className="font-medium">{task.title}</span>}
  maxHeight="24rem"        // a column's list scrolls past this
  tone="outline"           // "muted" (default) | "outline" | "ghost"
/>

Keyboard and gestures

Every one of these is in the component already. They are listed because a props table cannot mention a gesture, so nothing else on this page can tell you they exist.

DragLift a card into a ghost and carry it within or between columns. The board and tall columns scroll near their edges.
Long press (touch)Lift a card. A finger that moves first scrolls the board instead.
Space / EnterPick the focused card up, or drop it where it is.
Arrow up / downMove the picked up card within its column.
Arrow left / rightCarry it to the neighboring column.
Home / EndMove it to the top or the bottom of the column.
EscapePut the card back where it started. Works mid drag too.

Props

Read from the component's own type, so this cannot drift from what it accepts.

PropTypeDefaultDescription
columnsKanbanColumn<T>[]—The columns and their cards. Pair with `onChange` to control them.
defaultColumnsKanbanColumn<T>[]—The starting board when uncontrolled.
onChange(columns: KanbanColumn<T>[], move: KanbanMove<T>) => void—Called with the new board when a card lands somewhere new.
getKey(card: T) => string—A stable key per card, unique across the board. Defaults to `card.id`.
getCardLabel(card: T) => string—What screen readers call a card. Defaults to `label`, `title` or `name`.
renderCard(card: T, state: KanbanCardState) => React.ReactNode—The card's content. The surface is drawn around it.
maxHeightstring"28rem"Tallest a column's card list grows before it scrolls, any CSS length.
tone"muted" | "outline" | "ghost""muted"
size"sm" | "default" | "lg""default"
disabledboolean—
aria-labelstring"Board"
classNamestring—
columnClassNamestring—
cardClassNamestring—

More List components

View all List
  • 1Motion Sickness · Phoebe Bridgers3:50
  • 2Nobody · Mitski3:13
  • 3Pink + White · Frank Ocean3:04
  • 4Seventeen · Sharon Van Etten4:31
  • 5Cellophane · FKA twigs3:24
  • 6Holocene · Bon Iver5:36

Press Space or Enter to pick up a row. Use the arrow keys to move it, Space or Enter to drop it, and Escape to cancel.