Skip to content
Sign in
Apps SDKKanban widgetMenu

Kanban widgetPro

A small board for tasks made in the conversation, moved by drag, by one press, or entirely from the keyboard.

ProA launch board with two tasks the chat just made: drag, press a round mark to move on, or steer with the keyboard.

Installation

$ pnpm dlx shadcn@latest add @chatcn-pro/kanban-widget

Usage

tsx
import { KanbanWidget } from "@/components/ui/chatcn/pro/kanban-widget"

<KanbanWidget
  title="Corvo Serif launch"
  columns={[
    { id: "todo", title: "To do" },
    { id: "doing", title: "Doing", limit: 3 },
    { id: "done", title: "Done" },
  ]}
  tasks={tasks}
  onTasksChange={(next, move) => save(next, move)}
  onAdd={(column, title) => ({ id: newId(), title, column })}
/>

Tasks carry their column and keep their array order inside it. onTasksChange gets the whole list and, for moves, { id, from, to, index }, so a tool can sync one change instead of the board. Tasks with isNew (made by the chat a moment ago) carry a small accent mark until they move.

Three ways to move a task: drag it (a short long press starts the drag on touch, so the thread still scrolls), press its round mark to move it one column on, or focus it and press Space, steer with the arrow keys and press Space again; Escape puts it back. The last column reads as done, with a green check and muted titles.

Columns with a limit show count/limit and turn amber over it, with the reason for screen readers. Due dates are your words in due, tinted amber for soon and red for late. Below about 26 rem the columns stack, and drag still works across them. Render it inside the card your host draws for a widget answer. It fills the width it is given, so a comfortable max width (around 28 rem) comes from the card, and it follows the host theme through the kit tokens. Pass onExpand where the host can go full screen.

Examples

States

ProOver a limit with long titles, nothing done yet, no tasks, loading, an error and read only.

Props

PropTypeNotes
titleReactNode
columns{ id, title, limit? }[]The last column reads as done
tasks, defaultTasks{ id, title, column, assignee?, due?, dueTone?, isNew? }[]Order within a column follows the array
onTasksChange(tasks, move?) => voidEvery change, with the move when there is one
onAdd(column, title) => KanbanTask | undefinedShows Add task per column
status"ready" | "loading" | "error"Default ready
onRetry, onExpand() => void
disabledbooleanRead only
labelsPartial<…Labels>Every string the widget writes, for translation

Labels

labels covers the task count (tasks(total, done)), the limit note, the advance button (advance(title, to)), empty and add copy, every keyboard announcement (pickedUp, movedTo, dropped, cancelled) and the instructions read with each card.

Keyboard

KeyAction
TabInto the board, one card at a time
Arrow keysMove focus between cards and columns
Space or EnterPick the focused task up, or drop it
Arrow keys while holdingMove the task between columns, or up and down
Escape while holdingPut the task back where it was

Accessibility

  • Each column is a labelled region; each card is a focusable list item named with its title, assignee, due date and new mark, and described by the move instructions.
  • Every keyboard move is announced with the column and position. Arrow keys follow the reading direction in RTL.
  • The advance mark is a labelled button with a 32 px hit area (44 px on touch).
  • Due dates and limits carry words, never color alone.

Motion

A dragged card lifts with a shadow and a slight tilt and follows the pointer with no easing. Keyboard moves do not animate. Nothing else moves.