Skip to content

feat(Kanban): add Kanban compound component over createKanban - #1012

Open
johnleider wants to merge 9 commits into
devfrom
feat/kanban-component-518
Open

johnleider wants to merge 9 commits into
devfrom
feat/kanban-component-518

Conversation

@johnleider

@johnleider johnleider commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

closes #518

Adds the Kanban compound component over createKanban (part of #509).

Anatomy

Part Role
Kanban.Root Creates the createKanban board and a pointer-only useDragDrop context; owns the keyboard move model; emits move
Kanban.Column Registers a column; v-model is the column's item array; disabled and accept(value, from, index) gate moves
Kanban.List Drop zone (role="list") — direct parent of the column's items, exposes data-over
Kanban.Item Movable item identified by value (role="listitem", data-state="grabbed" | "dragging" | "idle")
Kanban.Instructions Keyboard instructions every item references via aria-describedby
Kanban.LiveRegion Polite live region for pick-up / move / drop / cancel / rejection announcements

The anatomy follows the composable's two tiers (board → column → item). List is split from Column because useDragDrop resolves the drop index against the zone element's direct children, so column headers and counters must live outside the zone.

Design notes

  • Data flow. The bound array per column is the source of truth. External changes (push, splice, replace) reconcile into the column's sortable; board moves write the new order back. Item identity is the value itself (===), so values must be unique across the board. Column reconciles through register / unregister / reorder, falling back to offboard + onboard when reorder is gated by disabled.
  • Keyboard, not drag-only. The default KeyboardAdapter nudges a pixel point, which can't express "one slot" or "next column" reliably, so the component installs only PointerAdapter (4px threshold so clicks on inner controls don't start drags) and implements a discrete model. Space/Enter picks up; arrows and Home/End move a virtual drop target without touching the board (RTL-aware; axes swap for orientation="vertical"). Cross-column steps skip columns that are disabled or whose accept(value, from, index) refuses the item, so keyboard users reach every column a pointer drag can. The target is previewed through data-target on the column and list and data-drop="before" | "after" on the neighbouring item, and each step is announced. Space/Enter commits a single transfer; Escape and blur discard the target with no board mutation. The pick-up is released when its item leaves the board and re-anchored after external changes. Focus follows the item when a drop remounts it in another column.
  • Events. move fires once per drop with { value, from, to, fromIndex, toIndex }, for pointer and keyboard alike, same-column and cross-column.
  • Locale. New Kanban.* strings in locale/messages/en, including aria-roledescription.
  • No composable changes. createKanban covered everything needed (transfer, per-column disabled / accept, browse for value lookup).
  • Size limit. useTheme already measures 8.56 kB on dev (the size job failed on feat(Otp): add Otp compound component over createOtp #787), so this carries the same 8.5 → 8.6 kB bump as feat(Virtualizer): add Virtualizer compound component over createVirtual #788 to keep the job green.

Checklist

  • packages/0/src/components/Kanban/ + barrel + components/index.ts
  • maturity.json: draft → preview, since: null, description
  • Docs page components/data/kanban.md + typed-router entry, examples (basic, wip-limit, move-log), components index entry, README
  • surface.test.ts, fixture + a11y.browser.test.ts entry (0 axe violations)
  • Unit (index.test.ts, 40 tests) and browser (index.browser.test.ts, 10 tests — real pointer drags, focus retention, keyboard skipping a rejecting column, RTL)
  • Changeset (@vuetify/v0: minor)

Adds Kanban.Root, Column, List, Item, Instructions, and LiveRegion.
Each Column bridges its item array through v-model; Root owns a
createKanban board, a pointer-only useDragDrop context, and a discrete
keyboard move model (pick up, arrow/Home/End steps, drop, Escape
cancel) with focus following the item across re-renders and
live-region announcements for moves and rejections.

closes #518
useTheme already measures 8.56 kB on dev, so the size job fails on any
packages change; same bump as #788.
@johnleider johnleider added this to the v1.3.0 milestone Oct 6, 2026
@johnleider johnleider self-assigned this Oct 6, 2026
Arrow keys now move a virtual drop target instead of transferring the
item on every step. The target skips columns that are disabled or whose
accept refuses the item, is exposed as data-target on the column and
list and data-drop on the neighbouring item, and is announced per step.
Space or Enter commits a single transfer, so move fires once per drop;
Escape and blur discard the target without touching the board. The
pick-up is released when its item leaves the board and re-anchored after
external reorders. aria-roledescription is now localized.
Drops the debounce advice now that keyboard moves commit once per drop,
documents data-target / data-drop, shows the preview in the basic and
WIP-limit examples, and registers /components/data/kanban in the typed
router.
Unlabelled item names, a throwing accept, index-dependent accept, a drop
refused after the target was set, and target re-anchoring when the
board changes mid-pickup.
… arrows

Passes the destination column into the per-step announcement instead
of re-resolving it.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant