Agent Task Queue
An agent task queue React component with drag-to-reorder, a breathing pulse on the running item, and finished tasks sliding out into a collapsible Done group.
Put it in a chat sidebar or below a message to show what the agent is about to do next. Unlike a fixed-order plan checklist, this is a queue that keeps getting consumed: users can drag to reorder or remove queued tasks, and failed tasks stay at the top of the queue waiting for a retry. Tasks are split into three sections — Running, Queued and Done. The running row breathes to show the agent is at work; when a task finishes, its loader cross-fades into a check mark, holds for a beat, then the whole row slides out and lands at the top of the Done group while the remaining rows FLIP into place. tasks is controlled by the parent; the component only presents the state changes.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add agent-task-queue.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<AgentTaskQueue/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
Installation
npx webberui@latest add https://webberui.com/r/agent-task-queue.en.jsonOr, once registries are configured in components.json, install it as @webberui/agent-task-queue.
Usage
import { AgentTaskQueue, type AgentTask } from "@/components/ui/agent-task-queue";
const [tasks, setTasks] = React.useState<AgentTask[]>([
{ id: "read", title: "Read this week's calendar", status: "running" },
{ id: "sum", title: "Write the summary", meta: "~2 min", status: "queued" },
{ id: "send", title: "Email the draft to myself", status: "queued" },
]);
<AgentTaskQueue
tasks={tasks}
onReorder={(ids) =>
setTasks((prev) => [
...prev.filter((t) => t.status !== "queued"),
...ids.map((id) => prev.find((t) => t.id === id)!),
])
}
onRemove={(id) => setTasks((prev) => prev.filter((t) => t.id !== id))}
onRetry={(id) =>
setTasks((prev) => prev.map((t) => (t.id === id ? { ...t, status: "queued" } : t)))
}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
tasks | AgentTask[] | — | The task list (controlled data); the parent updates statuses and the component animates rows in and out accordingly |
onReorder | (ids: string[]) => void | — | Called after queued tasks are reordered, with the new id order of the queued tasks; the drag handles are hidden when omitted |
onRemove | (id: string) => void | — | Called when a queued task is removed; when provided, an X button appears on hover / focus |
onRetry | (id: string) => void | — | Called when a failed task is retried; when provided, failed rows show a Retry button |
doneOpen | boolean | — | Controlled open state of the Done group; managed internally when omitted |
defaultDoneOpen | boolean | false | Initial open state of the Done group in uncontrolled mode |
onDoneOpenChange | (open: boolean) => void | — | Called when the Done group expands or collapses |
doneLabel | string | "Done" | Heading text of the Done group (the Chinese build defaults to "已完成", "Done") |
maxDoneVisible | number | 20 | Maximum rows shown in the Done group; the rest are summarised as "N more" |
stiffness | number | 450 | Stiffness of the layout spring (shared by reordering and slide in / out) |
damping | number | 36 | Damping of the layout spring |
pulseDuration | number | 1.6 | Seconds per breath of the running item |
colorDuration | number | 150 | Colour transition time in ms, written to --wb-agent-task-queue-duration |
className | string | — | Passed through to the outermost container |
AgentTask
| Field | Type | Default | Description |
|---|---|---|---|
id | string | — | Unique id used for the React key, drag reordering and layout animation pairing |
title | string | — | Task title |
detail | string | — | Secondary description |
status | "queued" | "running" | "done" | "failed" | "cancelled" | — | Current status |
icon | ReactNode | — | Decorative icon left of the title |
meta | string | — | Extra info on the right, e.g. "~2 min" |
How it works
- Three sections:
runninggoes to Running, pinned to the top and not draggable;queuedandfailedgo to Queued, withfailedpinned to the top in red;doneandcancelledgo to Done, withcancelledstruck through. - Finishing slide-out: when a status becomes
done, the loader cross-fades into a check mark over 150ms, holds for 300ms, then the row slides into the top of the Done group with a layout animation. If the group is collapsed, the row fades out instead, the header count rolls up digit by digit and the header flashes green. - Only the grip handle on the left picks a row up. While dragging, the order is held inside the component and
onReorderis called only on release; if the agent starts one of the queued tasks mid-drag, it is dropped from the draft order automatically. If the parent does not updatetasks, the order snaps back (controlled data). - No drag library is used — reordering and the FLIP fill-in come from
Reorderand the layout spring (stiffness/damping) inmotion/react. - Colour transitions read the CSS variable
--wb-agent-task-queue-duration, 150ms by default, adjustable withcolorDuration.
Accessibility
- Each section is a
role="list", each row a listitem with hidden status text (queued / running / done / failed / cancelled) - Status changes are announced through
aria-live="polite", e.g. "Done: Write the summary" - Keyboard reordering: focus a grip handle and press Space to enter move mode (
aria-pressed="true"), use the Up / Down arrows to swap, Space to drop and callonReorder, Escape to restore; moving focus away during move mode counts as a drop - The Done header is a
buttonwitharia-expandedandaria-controls; Remove and Retry buttons carry anaria-labelwith the task name, and the Remove button stays visible on touch devices - When the user has enabled reduce motion: no breathing, no spinning and no sliding — rows switch places directly with a 120ms fade; dragging still works but rows do not scale up
Tool Permission Card
A permission card for when an agent asks to run a tool: shows the tool name and a parameter summary with allow, deny and always-allow, then collapses into a one-line record once decided.
Stack Trace Viewer
A stack trace viewer that lists each frame, highlights your own code while folding library frames, expands a frame into its source snippet, and copies the trace in one click.