kanban-board
Columnar drag-and-drop board with user-defined columns, count badges, and optional WIP limits.
Overview
A web component that renders a columnar drag-and-drop board with user-defined columns. Each column wraps a <drag-surface> for native drag-and-drop and keyboard-accessible reordering and transfer. Supports any draggable content — user-story cards, plain articles, or custom elements. Includes auto-updating count badges, optional WIP (work-in-progress) limits with visual warnings, and optional column color tinting.
<kanban-board> <section data-column="backlog" data-column-label="Backlog"> <user-story draggable="true" data-id="PROJ-201" story-id="PROJ-201" persona="Sarah Chen" action="view all project timelines in one dashboard" priority="high" status="to-do" points="5" detail="minimal"> </user-story> </section> <section data-column="in-progress" data-column-label="In Progress"> <user-story draggable="true" data-id="PROJ-198" story-id="PROJ-198" persona="Jordan Park" action="filter reports by date range and team" priority="high" status="in-progress" points="5" detail="minimal"> </user-story> </section> <section data-column="review" data-column-label="Review"> </section> <section data-column="done" data-column-label="Done" data-column-color="success"> </section></kanban-board>
Attributes
| Attribute | Type | Description |
|---|---|---|
src | string | URL to JSON data for columns and items |
title | string | Optional heading displayed above the board |
compact | boolean | Reduced spacing variant for dashboard-style layouts |
Child Attributes
Set these on <section> children to define columns:
| Attribute | On | Type | Description |
|---|---|---|---|
data-column | <section> | string | Column identifier (e.g. "backlog", "doing", "done") |
data-column-label | <section> | string | Display label for the column header. Falls back to title-cased data-column |
data-wip | <section> | number | Optional WIP limit. Visual warning when exceeded |
data-column-color | <section> | string | Color token for column tint: success, warning, error, info |
Set these on draggable children within sections:
| Attribute | Type | Description |
|---|---|---|
draggable="true" | boolean | Required for drag capability (auto-added if missing) |
data-id | string | Stable identifier for the item (auto-generated if missing) |
WIP Limits
Add data-wip to any column section to set a work-in-progress limit. When the number of items in a column exceeds the limit, the component adds a data-wip-exceeded attribute to the column and fires a kanban-board:wip-exceeded event. Items are not blocked from entering — this is a visual warning only.
<kanban-board> <section data-column="backlog" data-column-label="Backlog"> <article draggable="true" data-id="task-1">Task A</article> <article draggable="true" data-id="task-2">Task B</article> </section> <section data-column="doing" data-column-label="In Progress" data-wip="2"> <article draggable="true" data-id="task-3">Task C</article> <article draggable="true" data-id="task-4">Task D</article> </section> <section data-column="done" data-column-label="Done"> </section></kanban-board>
Generic Content
The board is not limited to sprint planning. Any draggable content works — blog posts through a publishing pipeline, support tickets, hiring candidates, or content workflows.
<kanban-board> <section data-column="ideas" data-column-label="Ideas" data-column-color="info"> <article draggable="true" data-id="post-1"> <strong>CSS Container Queries Deep Dive</strong> <small>Tutorial</small> </article> </section> <section data-column="drafting" data-column-label="Drafting" data-wip="2"> </section> <section data-column="published" data-column-label="Published" data-column-color="success"> </section></kanban-board>
Events
| Event | Detail | Description |
|---|---|---|
kanban-board:transfer | { itemId, fromColumn, toColumn, newIndex, item } | Item moved between columns |
kanban-board:reorder | { itemId, column, oldIndex, newIndex } | Item reordered within a column |
kanban-board:ready | { columnCount, itemCount } | Fired after component initializes |
kanban-board:wip-exceeded | { column, limit, count } | Fired when a column exceeds its WIP limit |
JSON Data Mode
Set the src attribute to load board data from a JSON URL. Items with persona, action, or storyId fields are rendered as <user-story> elements. All other items are rendered as <article> elements.
{ "columns": [ { "id": "backlog", "label": "Backlog", "wip": null, "color": null, "items": [ { "id": "task-1", "text": "Design review" }, { "id": "PROJ-201", "storyId": "PROJ-201", "persona": "Sarah Chen", "action": "view timelines", "priority": "high", "detail": "minimal" } ] } ]}
Keyboard Navigation
All keyboard support is provided by the underlying <drag-surface> component:
- Tab to focus a column's drag surface
- Space or Enter to grab an item
- Up / Down to reorder within a column
- Left / Right to transfer between columns
- Space to drop the item
- Escape to cancel
Accessibility
- The columns container has
role="region"witharia-label="Kanban board" - Each drag-surface has an
aria-labelmatching the column label - A visually hidden live region announces all transfers for screen readers
- Count badges use
<output>elements for live value updates - Respects
prefers-reduced-motion: reduce
Related
<drag-surface>— the underlying drag-and-drop engine<story-map>— horizontal story map with activity columns<impact-effort>— 2×2 prioritization matrix<user-story>— Agile story cards to use as board items