Manual UI Templates Kanban

Kanban

elements man ui/templates/kanban

A board of columns of cards you reorder and move by pointer, touch or keyboard, with announcements and a one-column phone layout.

Example
import { Kanban, KanbanBoard, KanbanColumn, KanbanItem, KanbanItemMove, KanbanNav, KanbanNavItem, } from "@elements/ui/kanban"; <Kanban value={state.columns} label="Sprint board"> <KanbanNav> <KanbanNavItem e:for={id of Object.keys(state.columns)} e:key={(c) => c} value={id}>{TITLES[id]}</KanbanNavItem> </KanbanNav> <KanbanBoard> <KanbanColumn e:for={id of Object.keys(state.columns)} e:key={(c) => c} value={id} title={TITLES[id]} count={state.columns[id].length}> <KanbanItem e:for={task of state.columns[id]} e:key={(t) => t.id} value={task.id}> {task.title} <KanbanItemMove /> </KanbanItem> </KanbanColumn> </KanbanBoard> </Kanban>

Parts

Part What it is
Kanban The root. Owns value (two-way) and every drag; renders the drag overlay in the top layer.
KanbanBoard The row of columns (a stack when vertical). Scrolls on its main axis; snaps one column at a time on a phone.
KanbanColumn One column: a header from title and count, the card list (scrolls on its own), and header, actions and footer slots.
KanbanColumnHandle A grip button that drags its column. Columns reorder only with a handle or asHandle.
KanbanItem One card. It drags from a KanbanItemHandle, or as a whole card with asHandle; with neither it stays put.
KanbanItemHandle A grip button that drags its card; the rest of the card stays clickable and selectable.
KanbanItemMove Previous and next column buttons, the tap control every draggable needs on a phone. Shown in the compact layout by default.
KanbanNav A row of column buttons above the board on a phone: each scrolls to its column, and the one in view is current.
KanbanNavItem One column's button in KanbanNav.
.kanban-drop / .kanban-board-drop The placeholder that marks the slot while a card or column is over it.
.kanban-overlay The dragged copy, in the top layer, so a scrolling column never clips it.

Attributes

Kanban

Attribute Type Default Description
class string "" Extra classes on the part's root.

Kanban

Attribute Type Default Description
value Record<string, any[]> (two-way) {} Column id to its items; key order is column order. Written once per move, never during a drag.
getItemValue (item: any) => string | number item.id, else the item The id of an item. Must match its KanbanItem value.
orientation "horizontal" | "vertical" "horizontal" Columns side by side, or stacked.
label string "" The board's accessible name.
dragging { kind: "item" | "column"; id: string } | null (two-way) null What is being dragged. Bind it to render a custom overlay.
disabled boolean false Nothing drags and move buttons are disabled.
autoScroll boolean true Scroll the board, the column and the page when a dragged card nears their edges.
restrictTo "none" | "vertical" | "horizontal" | "board" | "window" "none" Lock the dragged copy to an axis, or keep it inside the board or the window.
keyboardCodes { start?: string[]; cancel?: string[]; end?: string[] } Space, Enter; Escape; Space, Enter, Tab The KeyboardEvent.code values that pick up, cancel and drop. Change instructions to name them.
flatCursor boolean false Default cursor instead of grab and grabbing.
announcements { start?, over?, end?, cancel? } {} Replace any screen reader message. Each gets { kind, label, column, position, total }; positions start at 1.
instructions string pick up, move, drop, cancel Screen reader instructions wired to every activator with aria-describedby.
roleDescription string "sortable" aria-roledescription on every activator; translate it with instructions and announcements.
onValueChange (value) => void () => {} After the board wrote a new value.
onMove (e: KanbanMoveEvent) => void () => {} Before a move is written: kind, id, from, to, value. e.preventDefault() keeps value (a limit, or a server that decides).
onDragStart (e: KanbanDragEvent) => void () => {} A card or column was picked up.
onDragOver (e: KanbanDragEvent) => void () => {} The slot under the drag changed (e.over).
onDragMove (e: KanbanDragEvent) => void () => {} Every pointer move and keyboard step while dragging.
onDragEnd (e: KanbanDragEvent) => void () => {} Dropped, moved or not.
onDragCancel (e: KanbanDragEvent) => void () => {} Escape, a lost pointer, blur, or a drop onMove refused cancelled the drag.

Kanban, KanbanColumn

Attribute Type Default Description
attrs Record<string, string | number | boolean | undefined> {} Other attributes for the root or the column: id, data-testid.

KanbanColumn

Attribute Type Default Description
value string (required) The column's key in value.
title string "" The header title; names the column.
count string | number "" A count tag beside the title.
label string "" The column's name when it has no title.
disabled boolean false Cannot be dragged and takes no cards.
asHandle boolean false A press anywhere on the column (not on a card or a control) drags it; its grab is the keyboard button.

KanbanItem

Attribute Type Default Description
value string | number (required) The item's id.
label string its text The name announcements use.
disabled boolean false Cannot be dragged or moved; others still move around it.
asHandle boolean false The whole card drags, even with a KanbanItemHandle inside. Without it or a handle the card does not drag.
attrs Record<string, string | number | boolean | undefined> {} Other attributes for the card: id, data-testid.

KanbanItemHandle, KanbanColumnHandle

Attribute Type Default Description
label string "Drag card" / "Drag column" The handle's accessible name.
disabled boolean false The handle does not drag; its card or column stays enabled.

KanbanItemMove

Attribute Type Default Description
show "compact" | "always" "compact" Show the move buttons only in the one-column layout, or always.
labels { to?, previous?, next?, noPrevious?, noNext? } "Move to {column}", "No previous column", "No next column" The buttons' accessible names, for translation. {column} in to is the target column's name.

KanbanNav

Attribute Type Default Description
label string "Columns" The nav's accessible name.
always boolean false Show at every width, not only in the one-column layout.

KanbanNavItem

Attribute Type Default Description
value string (required) The column it scrolls to.

KanbanItemHandle, KanbanColumnHandle, KanbanNavItem

Attribute Type Default Description
attrs Record<string, string | number | boolean | undefined> {} Other attributes for the button: id, data-testid, title.

Slots

Slot Part Content
default Kanban KanbanNav and KanbanBoard.
overlay Kanban Custom drag overlay content; replaces the copy of the dragged element while it has content.
default KanbanColumn The cards.
actions KanbanColumn The end of the header: a handle, a menu.
header KanbanColumn A header of your own, for a column without title.
footer KanbanColumn Below the cards: an add button.
default KanbanItem Card content.
icon KanbanItemHandle, KanbanColumnHandle The grip; a grip icon by default.

Keyboard

Keys Action
Space / Enter Pick up the focused card or column; press again to drop it.
ArrowUp / ArrowDown Move the card one slot in its column. On a vertical board, past the end into the next column. Move a column on a vertical board.
ArrowLeft / ArrowRight Move the card to the previous or next column at the nearest slot (flipped right to left). Move a column.
Home / End First or last slot.
Escape Cancel; the card returns.
Tab Next card or control. While lifted, drops and keeps focus on the card.
ArrowLeft / ArrowRight (nav) Move between column buttons.

Data attributes

Attribute Values On Description
data-orientation "horizontal" | "vertical" root, board
data-dragging "item" | "column" root While a drag runs.
data-dragging present card, column, activator On the one being dragged.
data-over present column The column a card would drop into.
data-disabled present root, column, card, handle
data-kanban-activator present card, handle, grab What takes the keys that start a drag.
data-kanban-surface present card, column Its grab is the button; a press on it drags.
data-active present .kanban-drop, .kanban-board-drop While it marks the slot.
data-source "pointer" | "keyboard" overlay
data-state "dragging" | "dropping" overlay
aria-current "true" nav item The column in view.

Accessibility

  • The board is a group named by label; each column is a group named by its title, and its cards are a list: each card sits in a listitem.
  • Every activator is a button (a handle, or role="button" on an asHandle card, so every draggable has one) and a tab stop with aria-roledescription="sortable" (roleDescription) and instructions wired by aria-describedby; it reports aria-pressed="true" while lifted and aria-disabled when it cannot move. A handle's aria-controls names the card or column it drags.
  • No control sits inside a role="button": an asHandle card that holds controls, and an asHandle column, get a grab instead, an empty button laid over them, named for them, which takes the keys and the focus ring while presses still drag the card or column. A grip inside an asHandle card or column is inert.
  • Pick up, every slot change, drop and cancel are announced in a live region with positions that start at 1 and the column's name.
  • Focus stays on the card during a keyboard drag and follows it into its new column on drop.
  • Every drag has a tap equivalent: KanbanItemMove's buttons are named for the column they move to and disabled at the ends.