TaskBoard
Horizontal status columns for the Tasks board view. Pair with TaskDnd for drag targets and TaskCard for items.
import {
TaskBoardColumn,
TaskBoardColumnBadge,
TaskBoardColumnChevron,
TaskBoardColumnCount,
TaskBoardColumnEmpty,
TaskBoardColumnEmptyAllowed,
TaskBoardColumnEmptyBlocked,
TaskBoardColumnEmptyIdle,
TaskBoardColumnHeading,
TaskBoardColumnItems,
TaskBoardColumnPanel,
TaskBoardColumnTrigger,
TaskBoardRoot,
TaskCard,
TaskDndProvider,
TaskDragOverlay,
TaskDraggable,
TaskDropPlaceholder,
TaskDropZone,
} from "raft-ui";
<TaskDndProvider isDropAllowed={() => true} onMove={() => {}}>
<TaskBoardRoot>
<TaskBoardColumn
render={<TaskDropZone id="task-status:todo" data={{ status: "todo" }} />}
>
<TaskBoardColumnTrigger>
<TaskBoardColumnHeading>
<TaskBoardColumnBadge status="todo" />
<TaskBoardColumnCount />
</TaskBoardColumnHeading>
<TaskBoardColumnChevron />
</TaskBoardColumnTrigger>
<TaskBoardColumnPanel>
<TaskBoardColumnItems>
<TaskBoardColumnEmpty>
<TaskBoardColumnEmptyIdle />
<TaskBoardColumnEmptyAllowed />
<TaskBoardColumnEmptyBlocked />
</TaskBoardColumnEmpty>
<TaskDropPlaceholder id="task-1" placement="before" />
<TaskDraggable
id="task-1"
dropId="task-1"
dropData={{ status: "todo", taskId: "task-1" }}
>
<TaskCard />
</TaskDraggable>
<TaskDropPlaceholder id="task-1" placement="after" />
</TaskBoardColumnItems>
</TaskBoardColumnPanel>
</TaskBoardColumn>
</TaskBoardRoot>
<TaskDragOverlay>
<TaskCard />
</TaskDragOverlay>
</TaskDndProvider>Wrap columns in TaskDndProvider and mount each column as a TaskDropZone. Drop policy and move handlers stay in the composition.
Keep one ScrollAreaViewport around the whole board. The viewport owns vertical and horizontal scrolling; TaskBoardRoot keeps its natural minimum width, so columns never become independent scroll regions.
Sparse tasks leave In Review / Done / Closed empty so TaskBoardColumnEmptyIdle shows. Drag onto an empty column for Allowed / Blocked copy (Closed is not blocked in this demo — see TaskDnd).
Keep one shared ScrollAreaViewport, and mount a useVirtualizer stack inside each tall column. Only viewport rows plus overscan stay mounted — watch the counter while scrolling. Virtualization stays consumer-owned; TaskBoard does not provide it.
Mount a virtual stack when a column can grow past the shared viewport. Only visible rows plus overscan stay in the DOM.
Mounted 0 / 48
API#WIP
| Prop | Type | Default | Description |
|---|---|---|---|
...props | useRender.ComponentProps<"div"> | — | Horizontal board layout root. |
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled collapsed state for the column. |
defaultOpen | boolean | false | Initial collapsed state for the column. |
...props | Collapsible.Root.Props | — | Fixed-width board column root. Compose TaskDropZone via render for DnD. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | Collapsible.Trigger.Props | — | Expands or collapses the board column. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | useRender.ComponentProps<"span"> | — | Heading row for column badge and count. |
| Prop | Type | Default | Description |
|---|---|---|---|
status | "todo" | "in-progress" | "in-review" | "done" | "closed" | — | Task status that drives the badge surface color. |
...props | useRender.ComponentProps<"span"> | — | Column status badge. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | useRender.ComponentProps<"span"> | — | Task count in the column heading. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | useRender.ComponentProps<"span"> | — | Disclosure chevron for the column trigger. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | Collapsible.Panel.Props | — | Collapsible panel hosting column items and empty states. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | useRender.ComponentProps<"div"> | — | Item list inside a board column. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | useRender.ComponentProps<"div"> | — | Empty-column host for idle, allowed, and blocked drop copy. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | useRender.ComponentProps<"span"> | — | Idle empty-column message. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | useRender.ComponentProps<"span"> | — | Allowed drop-target empty-column message. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | useRender.ComponentProps<"span"> | — | Blocked drop-target empty-column message. |