Svelte Kanban Board
A Kanban board is a data grid that draws its rows as cards instead of table rows. SvGrid treats it exactly that way: same <SvGrid>, same data, same columns, one extra board prop. Lanes are bucketed by a field on your rows, so a board and a table are two views of one dataset rather than two components to keep in sync.
Dragging a card does not mutate anything behind your back. The grid raises onCardMove with the card and its new lane, you assign the field on your own row object, and the board re-renders from your state. The same is true of the built-in card editor: it hands you a value, you decide what to store.
Install
npm i @svgrid/grid @svgrid/enterpriseThe grid and its data model are MIT-licensed in @svgrid/grid; this view ships in the commercial @svgrid/enterprise package and runs unlicensed while you evaluate.
The code
<script lang="ts">
import { SvGrid } from '@svgrid/grid'
import { enableBoardView } from '@svgrid/enterprise'
enableBoardView()
let data = $state([
{ id: 1, title: 'Design the board layout', status: 'backlog', assignee: 'Sam Rivera' },
{ id: 2, title: 'Lane drag and drop', status: 'in_progress', assignee: 'Lee Park' },
])
const columns = [
{ field: 'title', header: 'Task' },
{ field: 'status', header: 'Status' },
{ field: 'assignee', header: 'Assignee' },
]
</script>
<SvGrid {data} {columns} board={{ groupBy: 'status' }} />What you get
- Lanes from a field - groupBy names the field that buckets cards into lanes. Change it at runtime and the board re-buckets; the underlying rows never move.
- Drag, or the keyboard - Pointer drag-and-drop and Space plus arrow keys both move a card, so the board is usable without a mouse.
- WIP limits and swimlanes - Cap a lane with enforceWip, and cross the lanes with a second axis using swimlaneBy to get a grid of lane by owner.
- Cards you control - Take the built-in card with badges, sub-tasks and a progress bar, or pass your own snippet and render whatever the row needs.
- Virtualized to 50k cards - board.virtualized keeps only the visible cards in the DOM, so a lane with thousands of items still drags smoothly.
- Still a grid - Sorting, filtering and search run before the board renders, so a filter box above the board filters cards for free.
Live examples
- Kanban board mode - The same <SvGrid>, same data + columns, rendered as a Kanban board by setting one `board` prop: rows become cards in horizontal lanes bucketed by a `status` field. Built-in drag-and-drop AND keyboard move (Space + arrows) reassign the lane and reorder; double-click / F2 opens a built-in card editor; WIP limits, add-card, and a rich card snippet (assignee avatar + priority chip). Toggle Board / Table to see it is one grid.
- Sprint board (swimlanes + WIP) - An agile sprint board: status lanes crossed with a swimlane per assignee, an enforced WIP limit on In progress, and a story-point roll-up in every lane header via board.laneSummary. Drag across a band to reassign the owner; double-click to edit. Collapsible lanes.
- Sales pipeline (deal board) - A CRM deal board: stages as lanes with a live total-value roll-up per stage (board.laneSummary). Rich deal cards; drag to advance a deal, double-click to edit. Moves and edits persist to localStorage via onCardMove / onCardCommit, so a reload restores the board.
- Cards with sub-tasks & badges - The default board card made rich by config alone: label / due / assignee badges, a sub-task checklist with a progress bar (expand to tick items or add more), and a quick-add composer at the bottom of each lane. Double-click a card for the BUILT-IN detail drawer (board.drawer -> SvDrawer + SvForm with the UI-kit editors); toggle all fields vs a customized subset. Board / Table switcher.
- Group-by switch + reorderable lanes - Board structure, live: switch the lane axis at runtime (Status / Assignee / Priority) and the board re-buckets, and drag a lane header to reorder the columns. Both built-in - the group-by switch resets card positions to the new field; lane order is tracked and persists with persistKey. Board / Table switcher.
- Large board (virtualized) - Thousands of cards per lane kept smooth with board.virtualized - only the cards in view are in the DOM. A slider scales the board from 1k to 50k cards; drag-and-drop and keyboard move still work across the whole window.
Documentation
- Kanban board mode - Set one board prop and the grid renders its rows as cards in horizontal lanes instead of a table. It is the same <SvGrid>, the same data and columns - only…
- Kanban board over the same `$state` - You want a Kanban board backed by the same rows your grid already shows - one source of truth, switchable between a table and a board.
Related articles
- Building a Kanban Board in Svelte 5 (Without a Board Library) - How to turn a Svelte data grid into a drag-and-drop Kanban board with one prop - lanes, WIP limits, swimlanes, keyboard moves, and virtualized lanes for large boards.
- Building a Project / Task Board with a Svelte Data Grid - How to build a task management grid with grouping by status or assignee, inline edits, subtask tree rows, and saved views - without reaching for a dedicated project management tool.
Frequently asked questions
How do I build a Kanban board in Svelte 5?
Give <SvGrid> your data and columns and set the board prop with the field to bucket lanes by, for example board={{ groupBy: 'status' }}. Cards are your rows and lanes are that field's values.
Is the Kanban board free?
The grid, the board prop and its config types are MIT-licensed in @svgrid/grid. The board renderer ships in the commercial @svgrid/enterprise package, which runs unlicensed with a small watermark while you evaluate it.
How does the board write changes back to my data?
It does not write to your data at all. Moving a card raises onCardMove and editing one raises onCardCommit; you apply the change to your own state and the board re-renders from it.
Can I switch between a board and a table?
Yes, and that is the point of the design. The board is a view of the same grid, so toggling the board prop on and off swaps between cards and rows with no data changes.