TaskList
Stacked status sections for the Tasks list view. Compose TaskCard (and optionally TaskDnd) as children.
import {
TaskCard,
TaskListRoot,
TaskSection,
TaskSectionBadge,
TaskSectionChevron,
TaskSectionCount,
TaskSectionEmpty,
TaskSectionHeading,
TaskSectionItems,
TaskSectionPanel,
TaskSectionTrigger,
} from "raft-ui";
<TaskListRoot>
<TaskSection>
<TaskSectionTrigger>
<TaskSectionHeading>
<TaskSectionBadge status="todo" />
<TaskSectionCount />
</TaskSectionHeading>
<TaskSectionChevron />
</TaskSectionTrigger>
<TaskSectionPanel>
<TaskSectionEmpty />
<TaskSectionItems>
<TaskCard />
</TaskSectionItems>
</TaskSectionPanel>
</TaskSection>
</TaskListRoot>Group cards by status with collapsible sections. Collapse and counts are driven by the composition.
Use one ScrollAreaViewport around all status sections. The list remains a single vertical scroll surface, while TaskListRoot and sections only own their layout and collapse state.
Sparse tasks leave In Review / Done / Closed empty so TaskSectionEmpty shows. List has a single empty host (no DnD idle/allowed/blocked triad).
Keep one shared ScrollAreaViewport, and mount a useVirtualizer stack inside each tall section. Virtualization stays consumer-owned; TaskList does not provide it.
const viewportRef = useRef<HTMLDivElement>(null);
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => viewportRef.current,
getItemKey: (index) => items[index]!.id,
estimateSize: () => 116,
gap: 10,
overscan: 6,
});
<ScrollArea>
<ScrollAreaViewport ref={viewportRef}>
<TaskSectionItems>
<div style={{ height: virtualizer.getTotalSize(), position: "relative" }}>
{virtualizer.getVirtualItems().map((row) => (
<div
key={row.key}
ref={virtualizer.measureElement}
style={{ position: "absolute", transform: `translateY(${row.start}px)` }}
>
{renderItem(items[row.index]!)}
</div>
))}
</div>
</TaskSectionItems>
</ScrollAreaViewport>
</ScrollArea>API#WIP
| Prop | Type | Default | Description |
|---|---|---|---|
...props | useRender.ComponentProps<"div"> | — | List view root for TaskSection children. |
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled collapsed state for the section. |
defaultOpen | boolean | false | Initial collapsed state for the section. |
...props | Collapsible.Root.Props | — | List section root. Defaults to a section host via render. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | Collapsible.Trigger.Props | — | Expands or collapses the section. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | useRender.ComponentProps<"span"> | — | Heading row for 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"> | — | Section status badge. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | useRender.ComponentProps<"span"> | — | Task count in the section heading. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | useRender.ComponentProps<"span"> | — | Disclosure chevron for the section trigger. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | Collapsible.Panel.Props | — | Collapsible panel hosting empty state and items. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | useRender.ComponentProps<"div"> | — | List of task cards inside the section. |
| Prop | Type | Default | Description |
|---|---|---|---|
...props | useRender.ComponentProps<"div"> | — | Empty-state host for a section with no tasks. |