Kanban
Accessible, unstyled Kanban board: columns of cards with roving keyboard navigation and pointer + keyboard drag and drop (built on the shared drag-and-drop foundation), WIP limits, veto hooks, and announcements.
|
|
| Package |
@vizejs/ui/kanban |
| Maturity |
stable |
| Own the source |
vize lib pull kanban |
| Requires |
context, drag-and-drop, id |
| Aliases |
task board, kanban board, swimlanes, card board |
| Covers |
WAI-ARIA drag-and-drop guidance, dnd-kit sortable board, Atlassian board |
Usage
import { Kanban, KanbanCard, KanbanColumn } from "@vizejs/ui/kanban";
Or copy the source into your project with vize lib pull kanban (see Source Distribution).
API
Kanban<Card, ColumnId extends string>
Source: src/families/data/kanban/kanban.vue
Props
| Prop |
Type |
Default |
Description |
columns (required) |
readonly KanbanColumn<ColumnId>[] |
undefined |
Board columns in display order. |
modelValue (required) |
KanbanBoard<Card, ColumnId> |
undefined |
Cards per column (v-model). |
getCardKey (required) |
(card: Card) => string |
undefined |
Stable key per card. |
getCardLabel |
(card: Card) => string |
undefined |
Card name for announcements; defaults to the rendered text. |
canMove |
(card: Card, from: ColumnId, to: ColumnId) => boolean |
undefined |
Veto a move before it is offered as a drop target. |
id |
string | null |
undefined |
Consumer-owned board id. null and undefined select a deterministic fallback. |
dir |
"ltr" | "rtl" |
"ltr" |
Reading direction for Left/Right column navigation. |
instructions |
string |
"Press Space or Enter to pick up the card. …" |
Keyboard instructions referenced by every card's aria-describedby. |
announcements |
KanbanAnnouncements |
undefined |
Localized grab, move, drop, and cancel announcements. |
ariaLabel |
string |
undefined |
Accessible name of the board. |
Events
| Event |
Payload |
Description |
update:modelValue |
[value: KanbanBoard<Card, ColumnId>] |
Fired with the board after a move (supports v-model). |
move |
[event: KanbanMoveEvent<Card, ColumnId>] |
Fired after a move commits with origin and destination. |
Slots
| Slot |
Slot props |
Description |
column |
KanbanColumnSlotProps<Card, ColumnId> |
Column header contents. Defaults to the column title. |
card |
KanbanCardSlotProps<Card, ColumnId> |
Card contents. Defaults to the card label or key. |
empty |
{ readonly column: KanbanColumn<ColumnId> } |
Rendered inside columns without cards. |
Exposed
| Member |
Type |
Description |
element |
HTMLDivElement | null |
Rendered board element. |
focusCard |
(cardKey?: string) => void |
Focus a card by key (or the current tab stop). |
cancelDrag |
() => boolean |
Cancel an active drag. |
KanbanCard
Source: src/families/data/kanban/kanban-card.vue
Props
| Prop |
Type |
Default |
Description |
cardKey (required) |
string |
undefined |
Stable card key. |
columnId (required) |
string |
undefined |
Column the card is in. |
index (required) |
number |
undefined |
Zero-based index, published as aria-posinset (one-based). |
label |
string |
undefined |
Name used by drag announcements; defaults to the rendered text. |
disabled |
boolean |
false |
Keep the card focusable but not draggable. |
Slots
| Slot |
Slot props |
Description |
default |
{ readonly dragging: boolean } |
Card contents. Receives the drag state. |
KanbanColumn
Source: src/families/data/kanban/kanban-column.vue
Props
| Prop |
Type |
Default |
Description |
columnId (required) |
string |
undefined |
Column id. |
title (required) |
string |
undefined |
Column title and accessible name. |
count |
number |
0 |
Number of cards, published as aria-setsize context and data-count. |
limit |
number |
undefined |
WIP limit, published as data-limit. |
disabled |
boolean |
false |
Refuse drops. |
Slots
| Slot |
Slot props |
Description |
header |
— |
Column header contents. |
default |
— |
Cards (KanbanCard elements). |
Behavior
@vizejs/ui/kanban renders a board of labelled columns (kanban-column.vue) holding focusable cards
(kanban-card.vue); kanban.vue is the generic root (Card, ColumnId). Pointer and keyboard moves use
the shared drag-and-drop foundation (cards are sources and "before" targets; column lists are "end"
targets). Every row is proven by the named test in kanban.test.ts or kanban-ssr.test.ts.
| # |
State |
Input |
Outcome |
Proven by |
| K1 |
any |
render |
labelled board, role="group" columns named by their header, lists of listitem cards described by instructions |
renders labelled column groups with lists of focusable cards and instructions |
| K2 |
card focus |
arrows, Home/End |
roving focus moves within a column and across columns (index clamped, empty columns skipped) |
arrow keys move the roving focus within and across columns |
| K3 |
card focus |
Space, arrows, Enter |
keyboard drag cycles valid targets, drops into another column, emits move + update:modelValue, keeps focus |
keyboard drag moves a card into another column and keeps focus on it |
| K4 |
keyboard drag |
Escape |
cancels without moving |
Escape cancels a keyboard drag without moving |
| K5 |
limits and vetoes |
keyboard drag |
full (limit) and disabled columns and canMove vetoes are never offered as targets |
WIP limits, disabled columns, and canMove veto drop targets |
| K6 |
pointer drag |
release over a card's lower half |
the drop edge is published and the card lands after it |
dropping on a card's bottom edge inserts after it |
| K7 |
custom boards |
import |
KanbanColumn and KanbanCard parts are exported |
column and card parts are exported for custom boards |
| K8 |
SSR |
two requests + hydrate |
byte-identical markup with one tab stop and no drag state; warning-free hydration |
renders identical board markup across SSR requests and hydrates cleanly |