TaskListBlock
Add, assign, complete and filter actionable work with due-date context.
Plan idea 45, category Collaboration & workflow. Status experimental β see verification.
Import
import { TaskListBlock } from "@raydenui/ui/blocks";
import type { TaskListTask, TaskListAssignee, TaskListAddInput } from "@raydenui/ui/blocks";Usage
onToggleComplete is required: a completion control is never rendered without an
action. Every other control appears only when its handler is supplied, so the block cannot
show an add form, a delete button or a bulk action with nowhere to go.
const assignees: TaskListAssignee[] = [
{ id: "alex", name: "Alex Morgan", initials: "AM" },
{ id: "sam", name: "Sam Okafor", initials: "SO" },
];
const tasks: TaskListTask[] = [
{ id: "t1", title: "Confirm the Rotterdam booking", completed: false, assigneeId: "alex", dueDate: "2026-09-25" },
{ id: "t2", title: "Chase the missing bill of lading", completed: true, note: "Carrier replied on Friday." },
];
<TaskListBlock
title="Team tasks"
tasks={tasks}
assignees={assignees}
onToggleComplete={(id, completed) => setCompleted(id, completed)}
onAddTask={(input: TaskListAddInput) => createTask(input)}
onDeleteTask={(id) => deleteTask(id)}
onAssignTask={(id, assigneeId) => assign(id, assigneeId)}
/>;The block does not move a task to completed on its own. Re-render it with the new state.
Due dates
dueDate is a calendar date as YYYY-MM-DD, parsed in local time and never UTC-shifted.
Pass today to make the phrasing deterministic in tests, and formatDueDate to replace
the built-in wording.
<TaskListBlock
tasks={tasks}
onToggleComplete={setCompleted}
today={new Date("2026-09-23T09:00:00")}
locale="en-GB"
formatDueDate={(iso, { daysFromToday, completed }) =>
completed ? "Done" : daysFromToday < 0 ? `${-daysFromToday} days overdue` : iso
}
/>Selection and bulk actions
Selection is controlled. The bulk controls render only when their handler is supplied.
const [selectedIds, setSelectedIds] = useState<string[]>([]);
<TaskListBlock
tasks={tasks}
onToggleComplete={setCompleted}
selectedIds={selectedIds}
onSelectionChange={setSelectedIds}
onBulkComplete={(ids) => completeAll(ids)}
onBulkDelete={(ids) => deleteAll(ids)}
/>;Permission-aware editing
<TaskListBlock
tasks={tasks}
onToggleComplete={setCompleted}
canEdit={false}
readOnlyMessage="You can read this list but not change it."
/>Empty, no matches, loading, error
An empty source and a filter with no matches read differently.
<TaskListBlock
tasks={[]}
onToggleComplete={setCompleted}
emptyTitle="No tasks yet"
emptyDescription="Add the first thing this team needs to do."
noMatchesTitle="Nothing matches this filter"
noMatchesDescription="Try the All filter, or a different assignee."
/><TaskListBlock tasks={[]} onToggleComplete={setCompleted} status="loading" /><TaskListBlock
tasks={[]}
onToggleComplete={setCompleted}
status="error"
errorMessage="The task service is unavailable."
onRetry={() => refetch()}
/><TaskListBlock
tasks={tasks}
onToggleComplete={setCompleted}
onAddTask={createTask}
addStatus="error"
addErrorMessage="That task could not be created. Try again."
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
tasks | TaskListTask[] | β | Required. The complete set for the current page. |
onToggleComplete | (id: string, completed: boolean) => void | β | Required. |
title | string | β | Block title. |
description | string | β | Supporting sentence. |
headingLevel | "h1"β"h6" | "h2" | Element for title. |
onAddTask | (input: TaskListAddInput) => void | β | The add form is not rendered without it. |
onDeleteTask | (id: string) => void | β | No delete control is rendered without it. |
onAssignTask | (id: string, assigneeId: string) => void | β | Without it the assignee is shown but cannot be changed. |
assignees | TaskListAssignee[] | β | Also drives the assignee filter. |
selectedIds | string[] | β | Controlled selection. Controls render only with a handler. |
onSelectionChange | (ids: string[]) => void | β | Fired with the full resulting selection. |
onBulkComplete | (ids: string[]) => void | β | Bulk control renders only with this handler. |
onBulkDelete | (ids: string[]) => void | β | Bulk control renders only with this handler. |
status | "idle" | "loading" | "error" | "idle" | Lifecycle owned by your application. |
errorMessage | string | β | Shown when status="error". |
onRetry | () => void | β | The retry control renders only with a handler. |
addStatus | "idle" | "submitting" | "error" | "idle" | Add-form lifecycle. |
addErrorMessage | string | β | Shown when addStatus="error". |
canEdit | boolean | true | When false, completion is disabled and edit controls are omitted. |
readOnlyMessage | string | β | Explains why editing is unavailable. |
today | Date | now | Reference date for due-date context. |
locale | string | "en-GB" | BCP 47 tag used to format absolute dates. |
formatDueDate | (isoDate, context: TaskListDueContext) => string | β | Replaces the built-in phrasing. |
emptyTitle | string | β | Shown when there are no tasks at all. |
emptyDescription | string | β | Shown when there are no tasks at all. |
noMatchesTitle | string | β | Shown when tasks exist but none match the filters. |
noMatchesDescription | string | β | Shown when tasks exist but none match the filters. |
footer | ReactNode | β | Extra content below the list. |
className | string | β | Additional class names. |
TaskListTask
{ id, title, completed, assigneeId?, dueDate?, note? }. assigneeId resolves against
assignees.
TaskListDueContext
{ daysFromToday, date, completed }. daysFromToday is whole days; negative means
overdue.
States
- idle β the task list.
- loading / error β with an optional retry control.
- empty β no tasks at all.
- no matches β tasks exist but none match the current filters.
- read-only β no permission to edit.
- add submitting / add error β the add formβs own lifecycle.
- partial selection β the select-all control reports a mixed state.
Verification
No batch verification report exists for this block. The recorded evidence is its own 17 stories β including adding a task, completing a task, a filter with no matches, a partial selection reporting mixed, fifty tasks, read-only, loading, a failed load, a failed add, an add in flight, a completion-only configuration, long titles, a themed surface and a narrow container β and the repository story suite, re-run on 23 September 2026.
Not verified: a measured width, contrast or interaction sweep of the kind Batch A and Batch C recorded; a screen-reader pass; any non-Chromium engine; operating-system text-size settings.
Known limitations
- The status and assignee filters are local UI state over the supplied
tasks. There is no prop to set or observe them, so server-side filtering is not expressible. tasksis the complete set for the current page. The block owns no pagination.