Kanban board

Moves and reorders cards across named columns with drag and keyboard alternatives.

Use the move buttons, or focus a card handle and press Alt with Arrow up or Arrow down. Scroll horizontally to see more columns.

Planned1

  1. Write the brief

Active1

  1. Explore layouts

Complete1

  1. Collect references

From proof to press

Use the move buttons, or focus a card handle and press Alt with Arrow up or Arrow down. Scroll horizontally to see more columns.

To do1

  1. Choose the paper
    Compare the two uncoated stocks.

In progress1

  1. Review the proof
    Final copy and registration.

Done1

  1. Set the type

Use it for

  • Finite work items moving through named states.
  • Column changes and ordering that should remain keyboard accessible.

Not for

  • A large virtualised issue tracker or automatic workflow rules.

Three ways in. They share one source, so the pixels match whichever you pick.

1. Import the package

npm install @noorddev/vlak-react

// once, next to your app's root
import "@noorddev/vlak-react/css";

import { KanbanBoard } from "@noorddev/vlak-react";

Precompiled React and one stylesheet. No compiler to configure. Per-component imports work too: @noorddev/vlak-react/components/kanban-board.

2. Vendor the source

npx @noorddev/vlak-cli add kanban-board

The StyleX leaf lands in components/vlak/ with its dependencies, for your own compiler to own. See StyleX.

3. Through shadcn

npx shadcn add https://vlak.dev/r/kanban-board.json

The same registry item, installed by shadcn's CLI.

CSS only

<link rel="stylesheet" href="node_modules/@noorddev/vlak/css/vlak.css" />

No React. Link vlak.css and use the markup and classes below.

import { KanbanBoard } from "@noorddev/vlak-react";

<KanbanBoard columns={[{ id: "todo", label: "To do" }, { id: "doing", label: "In progress" }, { id: "done", label: "Done" }]} value={cards} onValueChange={setCards} />

KanbanBoard

Movable cards with drag, keyboard reordering, and named destination selectors.

PropTypeDefaultDescription
columnsrequiredreadonly KanbanColumn[]
valueKanbanCard[]
defaultValueKanbanCard[][]
onValueChange(cards: KanbanCard[]) => void
labelstring"Board"

Also accepts Omit<HTMLAttributes<HTMLDivElement>, "defaultValue">.

KeysDoes
Alt+Arrow up, Alt+Arrow downReorders the focused card handle within its column.
Tab, Enter, SpaceOperates move up and down buttons and each card's native destination selector.
<div class="rs-kanban-board" role="region" aria-label="Board"><div class="rs-kanban-columns"><section class="rs-kanban-column"><h3 class="rs-kanban-heading">In progress</h3><p class="rs-kanban-card">Review the proof</p></section></div></div>
.rs-kanban-board.rs-kanban-columns.rs-kanban-column.rs-kanban-heading.rs-kanban-list.rs-kanban-card.rs-kanban-card-header.rs-kanban-title.rs-kanban-detail.rs-kanban-controls.rs-kanban-destination.rs-kanban-reorder.rs-kanban-action.rs-kanban-status.rs-kanban-help