Columns and Ordering
Columns describe your workflow, such as To do → In progress → Done. A card’s status must match a column’s prop; the visible name can be friendlier.
Organize your workflow
Columns represent the status stored on each card.
Try it: Collapse Done, expand it again, or change the column order.
What to notice: Only the presentation changes; cards keep their status.
TypeScript source
Install the packages from Getting Started, then use this source in your app.
import type { KanbanPlugin, KanbanConfig } from '@revolist/kanban';import type { WorkCard } from './first-board';
export function moveResearch(kanban: KanbanPlugin<WorkCard>, columnProp: string) { return kanban.moveCards(['task-1'], { columnProp });}export function moveResearchToPlatform(kanban: KanbanPlugin<WorkCard>) { return kanban.moveCards(['task-1'], { columnProp: 'todo', swimlaneId: 'platform' });}export function selectTodoCards(kanban: KanbanPlugin<WorkCard>) { kanban.setSelectedCardIds(kanban.getCards().filter(card => card.status === 'todo').map(card => card.id));}export const workInProgress: Partial<KanbanConfig<WorkCard>> = { columns: [{ prop: 'todo', name: 'To do' }, { prop: 'doing', name: 'In progress', wipLimit: 1 }, { prop: 'done', name: 'Done' }], wipBehavior: 'block',};export const startBeforeDone: Partial<KanbanConfig<WorkCard>> = { rules: { canDrop: ({ cards, targetColumn }) => targetColumn.prop === 'done' && cards.some(card => card.status === 'todo') ? 'Start the task before marking it done.' : true },};export function frenchBoard(config: KanbanConfig<WorkCard>): KanbanConfig<WorkCard> { return { ...config, locale: 'fr-FR', columns: config.columns?.map(column => ({ ...column, name: ({ todo: 'À faire', doing: 'En cours', done: 'Terminé' } as Record<string, string>)[String(column.prop)] ?? column.name })), labels: { ...config.labels, emptyColumn: 'Aucune carte', dropCardHere: 'Déposer une carte ici', moveCancelled: 'Déplacement annulé', editCard: 'Modifier la carte', deleteCard: 'Supprimer la carte' } };}import { defineCustomElements } from '@revolist/revogrid/loader';import { KanbanPlugin, type KanbanConfig } from '@revolist/kanban';import '@revolist/revogrid-pro/styles.css';import '@revolist/kanban/styles.css';
export interface WorkCard { id: string; title: string; status: string; order: number; description?: string; team?: string; owner?: string; priority?: string; tags?: string[]; progress?: number; startDate?: string; endDate?: string;}export const demoCards: WorkCard[] = [ { id: 'task-1', title: 'Research customer needs', description: 'Collect feedback for the next release.', status: 'todo', team: 'product', owner: 'Ana', priority: 'normal', order: 1000 }, { id: 'task-2', title: 'Build onboarding', description: 'Make the first session useful.', status: 'doing', team: 'product', owner: 'Mia', priority: 'high', order: 1000 }, { id: 'task-3', title: 'Improve API errors', description: 'Return actionable validation messages.', status: 'todo', team: 'platform', owner: 'Rui', priority: 'normal', order: 2000 }, { id: 'task-4', title: 'Release checklist', description: 'Ready for the next deployment.', status: 'done', team: 'platform', owner: 'Sam', priority: 'normal', order: 1000 },];export const boardConfig: KanbanConfig<WorkCard> = { columns: [{ prop: 'todo', name: 'To do', size: 210 }, { prop: 'doing', name: 'In progress', size: 210 }, { prop: 'done', name: 'Done', size: 210 }], card: { titleField: 'title' }, cardRowHeight: 88, addCard: false, swimlaneColumn: false,};
export async function configureBoard( grid: HTMLRevoGridElement, config: KanbanConfig<WorkCard> = boardConfig, cards: readonly WorkCard[] = demoCards, extraPlugins: HTMLRevoGridElement['plugins'] = [],) { await defineCustomElements(); grid.plugins = [KanbanPlugin, ...extraPlugins]; // The packaged editor and history install automatically. grid.columns = [{ prop: 'title', name: 'Title' }, { prop: 'status', name: 'Status' }, { prop: 'owner', name: 'Owner' }]; // Cached remote data can hydrate immediately: finish initial grid setup first. grid.kanban = config.remote ? { ...config, remote: false } : config; grid.source = cards.map(card => ({ ...card })); await grid.componentOnReady(); const plugins = await grid.getPlugins(); const kanban = plugins.find((plugin): plugin is KanbanPlugin<WorkCard> => plugin instanceof KanbanPlugin); if (!kanban) throw new Error('Kanban could not start.'); if (config.remote) grid.kanban = config; return kanban;}
// Give your container a width and mount once after it exists in the DOM.export async function createKanbanBoard(container: HTMLElement) { await defineCustomElements(); const grid = document.createElement('revo-grid'); grid.style.cssText = 'display:block;width:100%;height:400px'; container.append(grid); try { const kanban = await configureBoard(grid); return { grid, kanban, destroy() { grid.remove(); } }; } catch (error) { grid.remove(); throw error; }}Try it: reorder or collapse a column, then Reset. Moving a column changes the board layout; it does not change any card’s status.
Start with Your First Board. The snippets below extend that grid; config denotes your existing Kanban configuration.
Workflow columns
Section titled “Workflow columns”kanban.columns is the workflow schema; grid.columns remains the canonical
table/card-field schema. A card belongs to a workflow column when
card[columnField] === column.prop.
Workflow definitions reuse the safe RevoGrid header and sizing subset and add Kanban behavior such as WIP limits, collapse state, transition rules, metadata, and card filtering.
The array is optional and defaults to []. This supports loading workflow
metadata and cards independently: no columns plus no cards is an empty board,
while cards without configured columns use the managed Unmapped column by
default. Supplying workflow columns later rebuilds the projection from the same
canonical grid.source records.
columns: [ { prop: 'queued', name: 'Queued', size: 260 }, { prop: 'active', name: 'Active', minSize: 240, maxSize: 360, wipLimit: 4, allowedFrom: ['queued', 'active'], collapsible: true, },]Projected workflow columns keep the exact authored prop; no synthetic grid
property is introduced. If name is omitted, Kanban displays String(prop).
The default size is 288 and minSize is 220. The core column-move plugin
handles header dragging; kanbancolumnorderchange exposes the resulting prop
order for persistence.
Every workflow column is collapsible by default. Set collapsible: false to lock a column open, or use collapsed: true for its initial state. At runtime, setColumnCollapsed(prop, collapsed) changes one column and getCollapsedColumnProps() returns the active collapsed set. A collapsed column remains visible as a narrow rail with a vertical resolved-name badge, so users can restore it without losing board context.
Card order inside a column
Section titled “Card order inside a column”Set a numeric order on each card. Kanban assigns ranks between neighbors when you move a card and may rebalance a destination bucket when its ranks become too close. Save every record in the committed changedCards batch, including neighbors whose ranks changed.
Table sorting does not reorder cards while the board is active; orderField is authoritative. To rename source properties, use field mapping.
Common mistakes
Section titled “Common mistakes”grid.columnsdescribes table/card fields;grid.kanban.columnsdescribes workflow stages.- Changing a column label does not rename the status values in your records.
- Unknown statuses go to Unmapped by default; fix the data or configure the intended workflow.
Next steps
Section titled “Next steps”Continue with swimlanes, moving cards and server-side saving. See the Kanban API for exact types and signatures.