Component
Kanban
<DomKanban>A controlled, API-shaped Kanban for shared resource rows, custom Vue card renderers, async creation, and precise card or column ordering.
Demo
A practical todo board
Drag anywhere over a column to target its nearest insertion point; the board opens a card-sized placeholder so empty columns and exact ordering remain obvious. On drop, the destination is committed immediately while the dimmed source card folds closed. Hold near the top or bottom of a long column to auto-scroll it. Reorder columns by their grip, or add local columns and cards. The createCard hook emulates a remote POST and returns the server-owned id before update:rows is emitted.
Todo board
To do
2Ideas and unstarted work.
Write the launch checklist
Collect owners and exit criteria.
Review empty states
Cover first-run and filtered results.
Doing
1/3Work currently in progress.
Test mobile navigation
Done
1Completed this week.
Publish release notes
Drag a card, reorder a column, or add a todo.
Shared resources
One list across Kanban, grid, and calendar
The view switch belongs to the application because each view may have different query, pagination, and editing rules. The underlying feature records do not change shape: status and position drive Kanban, status remains a normal grid column, and dueDate drives the calendar.
Product features
Backlog
1Team invitation roles
Planned
2Invoice PDF export
Saved grid filters
Active
2/3Usage alert emails
Workspace audit log
Complete
1Billing portal refresh
All three views receive the same resources array. Kanban maps status and position; the grid exposes status as a select column; the calendar maps dueDate.
Custom cards
Application-defined feature cards
Pass cardComponent for a reusable application card, set component on an individual column, or use the card slot for inline control. DomKanban retains ordering, keyboard movement, focus, and drag semantics around the custom renderer.
Product delivery board
Discovery
1Validate the problem and expected outcome.
Live dispatch overview
Give coordinators one map for technician locations and delayed jobs.
Maya Chen
Due 14 Aug
Delivery
2Design and implementation in progress.
Receipt capture review
Let finance compare extracted fields against the original receipt.
Owen Reed
Due 18 Aug
Saved operational views
Save filters, sorting, and display preferences across data surfaces.
Priya Shah
Due 21 Aug
Validation
1QA, rollout, and customer feedback.
Keyboard move semantics
Verify card and column movement without a pointer.
Maya Chen
Due today
Custom cards can emit application actions without owning navigation.
Architecture
Controlled data and transport boundaries
DomKanban never sends a request and never mutates a supplied row. A successful interaction emits an immutable update:rows projection for local or optimistic state plus a detailed card-move payload for persistence. Use v-model:rows for a local board, or listen to the payload and reconcile it through a store for server data.
The move payload includes minimal changes for the moved row and complete key-only orders for every affected column. A backend can update the status field and all affected positions in one transaction without reconstructing intent from neighbouring records.
Card and column creation use optional promise-aware hooks because the component sometimes needs a server id before it can publish the next controlled array. A hook can POST the suggested record and return the complete saved resource or only its id. Rejections leave the composer open and emit a typed error event.
View orchestration stays above the components. A data grid may paginate a million rows remotely, while a Kanban usually requests one scoped board and a calendar requests a date window. Keeping the switcher application-owned avoids pretending those queries are interchangeable while preserving one resource schema.
Reference
Props
Control props
| Name | Type | TS | Default | Description |
|---|---|---|---|---|
rows | array | Array<unknown> | [] | Resource rows shared with a grid, calendar, API, or application store. |
columns | array | Array< | [] | Ordered Kanban column definitions. Keys should match values stored by columnKey. |
rowKey | string | function | string | 'id' | Field name or function used to identify each resource row. |
columnKey | string | string | 'status' | Row field that assigns a resource to a Kanban column. |
orderKey | string | string | 'position' | Row field that stores the zero-based order within a column. |
titleKey | string | function | string | 'title' | Field name or function used by the built-in card renderer for its title. |
descriptionKey | string | function | string | 'description' | Field name or function used by the built-in card renderer for supporting text. |
cardComponent | object | function | string | Record<string, unknown> | — | Vue component used to render every card. A column component or card slot can override it. |
Creation
| Name | Type | TS | Default | Description |
|---|---|---|---|---|
createCard | function | Function | — | Optional async hook that persists a suggested row and returns a row or stable id. |
createColumn | function | Function | — | Optional async hook that persists a suggested column and returns a column or stable key. |
allowAddCards | boolean | boolean | true | Show a compact title composer at the bottom of each enabled column. |
allowAddColumns | boolean | boolean | true | Show a column composer after the final board column. |
Interaction
| Name | Type | TS | Default | Description |
|---|---|---|---|---|
dragCards | boolean | boolean | true | Allow native pointer drag/drop and Alt+Arrow keyboard card movement. |
reorderColumns | boolean | boolean | true | Allow columns to be reordered with the grip or Alt+Left/Right. |
cardDraggable | boolean | function | boolean | true | Boolean or function that decides whether an individual card can move. |
canDrop | function | Function | — | Optional application rule that receives source and target context before a drop. |
Labels
| Name | Type | TS | Default | Description |
|---|---|---|---|---|
boardLabel | string | string | 'Kanban board' | Accessible name for the board region. |
resourceLabel | string | string | 'cards' | Human label used in card counts and announcements. |
addCardLabel | string | string | 'Add card' | Label for each column creation control. |
addColumnLabel | string | string | 'Add column' | Label for the board column creation control. |
emptyText | string | string | 'Drop a card here or add a new one.' | Default text shown in an empty column. |
Layout
| Name | Type | TS | Default | Description |
|---|---|---|---|---|
columnWidth | string | number | string | '18rem' | Fixed width of each horizontally scrolling column. |
height | string | number | string | '36rem' | Height of the board viewport. |
State
| Name | Type | TS | Default | Description |
|---|---|---|---|---|
disabled | boolean | boolean | false | Disable creation and reordering while keeping the board readable. |
loading | boolean | boolean | false | Show a non-blocking loading indicator over the board. |
Auto-generated from Kanban.props and inline _edit hints.
Events
| Name | Payload | Description |
|---|---|---|
| @update:rows | Array<Record<string, unknown>> | Immutable local projection after a completed card move or creation. Use v-model:rows for local boards. |
| @update:columns | Array<KanbanColumn> | Immutable ordered columns after a completed reorder or creation. |
| @card-move | KanbanCardMove | Fired after a valid pointer or keyboard move. Persist changes and orders to a resource API. |
| @card-drop | KanbanCardMove | Alias emitted with card-move for applications that model drag/drop events. |
| @card-create-request | ({ column, columnKey, index, draft, suggestedRow }) | Fired before the optional createCard hook runs. |
| @card-create | ({ column, columnKey, index, draft, result, row, nextRows }) | Fired when the creation hook succeeds or a local suggested row is accepted. |
| @card-create-error | ({ column, columnKey, draft, error }) | Fired when createCard rejects. |
| @column-move | ({ column, columnKey, sourceIndex, targetIndex, columnKeys, nextColumns, input }) | Fired after a valid pointer or keyboard column reorder. |
| @column-create-request | ({ label, suggestedColumn }) | Fired before the optional createColumn hook runs. |
| @column-create | ({ label, result, column, nextColumns }) | Fired when the column creation hook succeeds or a local suggestion is accepted. |
| @column-create-error | ({ label, error }) | Fired when createColumn rejects. |
| @card-click | ({ row, rowKey, column, columnKey, index, event }) | Fired when a card shell is activated without using an inner interactive control. |
| @card-action | ({ row, rowKey, column, columnKey, index, action, payload }) | Re-emitted when a custom card component emits action. |
| @card-drag-start | ({ row, rowKey, source, event }) | Fired when native card dragging begins. |
| @card-drag-end | ({ row, rowKey, source, event }) | Fired when native card dragging ends. |
Names auto-detected from defineEmits and source emit() calls; payload and description from __doc.events when present.
Slots
| Name | Scope | Description |
|---|---|---|
| #card | { row, rowKey, column, columnKey, index, drag } | Custom card renderer. The component retains the accessible focus and drag shell. |
| #column-header | { column, columnKey, index, rows, count, limit } | Custom content for a column header. |
| #empty | { column, columnKey } | Custom empty-column state. |
| #card-composer | { column, columnKey, draft, setDraft, submit, cancel, creating } | Custom card creation form. |
| #column-composer | { draft, setDraft, submit, cancel, creating } | Custom column creation form. |
| #column-footer | { column, columnKey, rows, count } | Extra content below a column card list. |
Keyboard
- Alt + Up / DownMove the focused card within its current column.
- Alt + Left / RightMove the focused card into the adjacent column.
- Alt + Left / Right on column gripReorder the current column.
- EnterSubmit the built-in card or column composer.
- EscapeClose the active composer.