Components/TaskRows

TaskRows

Agent task status rows with a progress ring, status pills, and expandable execution detail.

VerifiedSince 0.3.9

TaskRows

Basic Usage

Capsules

Each row is its own card, and the corner radius tightens from 22px to 14px as it opens — the signature move of this variant. The status run's timeline belongs to the demo.

Loading demo...

List

The same rows inside a single card, divided by hairlines, with the radius pinned at 0.

List variant

For panels already inside a card, so no second container is stacked on top.

Loading demo...

Status Badges and Replay

done and error draw a solid circular mark with a pop-in entrance; running and pending draw a 24px ring that can hold a step number. The running ring is a constant 28% arc that rotates as a whole — upstream's comment describes a sweep from 0 to 66%, but that sweep does not exist in the code, so do not implement it.

Both the badge and the pill carry :key="row.status". Vue reuses the same element otherwise, and a both-filled animation never replays on a reused element; changing the key forces a rebuild so the pop-in and fade-in actually run on a status change.

API

Props

PropTypeDefaultDescription
rowsTaskRowItem[]The task rows. Required.
variant'capsules' | 'list''capsules'Container form.
defaultOpenIdsstring[]Ids open before any interaction. Ignored while openIds is bound.
openIdsstring[]Bind it and the host owns the open set; leave it unbound and the component keeps it.
doneTextstring'Completed'Pill text for done rows.
errorTextstring'Failed'Pill text for error rows.
runningTextstringNo default: a running row shows no pill, matching upstream.
pendingTextstringNo default: a queued row shows no pill.

TaskRowItem is { id, label, status, amount?, index?, statusText?, details?, retryable? }. status is 'pending' | 'running' | 'done' | 'error', aligned with AiToolCallPart; details is { label, meta? }[].

Events

EventPayloadDescription
toggle(id: string, open: boolean)Emitted when a row is clicked, carrying its id and the state after the toggle.
update:openIds(ids: string[])Emitted whenever the open set changes; usable as v-model:open-ids.

Slots

NameScopeDescription
badge{ row }Replaces the badge area (mark or ring).
detail{ row, detail, index }Replaces the rendering of one detail line.
trailing{ row }Renders host controls outside the toggle button.

Interaction Contract

  • The open set is controlled/uncontrolled dual-mode: unbound, the component keeps it; bound, the host owns it outright. update:openIds fires in both cases.
  • Every row's collapse has its own id, and the header button points at it with aria-controls. While closed it carries inert, taking the detail out of the tab order too.
  • statusText takes precedence over the four per-status text props.
  • The turning arrow on a failed row indicates that a retry is under way; it is not a control. It sits inside the toggle button, where a real button would be invalid nested interactive content. Turn it off with retryable: false. For an actual retry control use the trailing slot, which renders outside the toggle.
  • Detail entrance delay runs through --tx-bui-task-rows-detail-index and row entrance through --tx-bui-task-rows-index, neither as inline styles.
  • The collapse does not unmount its content: a closed row's details stay in the DOM at zero height.
  • Under reduced motion the radius morph, rotation, and entrances all stop, while status itself keeps advancing.

Best Practices

  • Use capsules for a task group floating on the page and list for panels already inside a card — the latter avoids stacking a second container shadow.
  • Leaving running and pending without pills is closer to upstream; pass runningText / pendingText only when you actually need them.
  • Use the ring's index to express "step N". Once a row finishes, the badge becomes a mark and the number goes away on its own.
  • Put a right-aligned quantity in amount ("12 suppliers"); it renders in tabular figures so it does not jitter as values stream in.
  • Use a detail's meta for ratios and counts in tabular figures, and say what happened in label.
  • The component sizes to its container; upstream's 440px frame is the host's decision.

Source

  • Component source: packages/tuffex/packages/components/src/task-rows/src/TxTaskRows.vue.
  • Types: packages/tuffex/packages/components/src/task-rows/src/types.ts.
  • Verified coverage: packages/tuffex/packages/components/src/task-rows/__tests__/task-rows.test.ts (21 cases) covers controlled and uncontrolled open sets, one-to-one aria-controls, inert while collapsed, the badge element genuinely being rebuilt on a status change, the constant 28% arc, pill defaulting, and trailing landing outside the button.
  • Adapted from Beautiful UI (https://www.beautifului.dev), © 2026 Shane Levine, MIT.
查看源码
packages/tuffex/packages/components/src/task-rows/index.ts