a1ui
6 new components shipped

Status Capsule

A collapsible task summary with a progress ring, file details, and retry states.

Read agent guide

Demo

  • thumbnails.svg96 KBReady
  • tokens.json12 KBReady
  • component.tsx36 KBReady
Simulated export
Export ready. Ready.

Run the export, then collapse it to keep just the summary. Preview an interruption to try the retry state.

Installation

pnpm dlx shadcn@latest add https://ui.arjayby1.xyz/r/status-capsule.json

Code

"use client";

import { StatusCapsule, type StatusCapsuleTask } from "@/components/ui/status-capsule";

const tasks: StatusCapsuleTask[] = [
  { id: "thumbnails", label: "thumbnails.svg", detail: "96 KB", status: "success" },
  { id: "tokens", label: "tokens.json", detail: "12 KB", status: "running" },
  { id: "component", label: "component.tsx", detail: "36 KB", status: "ready" },
];

export function ExportStatus() {
  return (
    <StatusCapsule
      title="Exporting files"
      description="1 of 3 files · 48%"
      status="running"
      progress={48}
      tasks={tasks}
      footer="Your export will appear in Downloads."
    />
  );
}

API reference

PropTypeDefaultPurpose
status"ready" | "running" | "success" | "error"RequiredOverall job state, progress treatment, and announced feedback.
tasksreadonly StatusCapsuleTask[]RequiredTask rows with stable, unique id, label, and status.
titlestringState labelSummary text. Defaults to Ready, In progress, Complete, or Needs attention.
descriptionstringCompleted task countSecondary summary text.
progressnumberNonePercentage, clamped to 0–100. Omit during a running job for an indeterminate ring.
action{ label: string; onClick: () => void; disabled?: boolean }NoneOptional action below the tasks. The caller controls its label, handler, and availability.
footerReactNodeNoneOptional note, link, or custom controls below the tasks.
expandedbooleanUncontrolledControls whether task details are open.
defaultExpandedbooleantrueInitial open state when uncontrolled.
onExpandedChange(expanded: boolean) => voidNoneReceives changes from the trigger or Escape key.
classNamestringNoneOuter layout classes.
styleCSSPropertiesNoneInline styles and component theme tokens.

Each task accepts an optional detail string and icon React node. Task states are independent of the overall job state. Keep both in sync with your job data. Ready tasks show Ready, running tasks show In progress, successful tasks show Complete, and failed tasks show Needs attention.

The component displays data supplied by your application. It does not upload files, run jobs, retry requests, or write downloads. Connect action.onClick to your job handler, update status, tasks, and progress from your application, and set action.disabled while the action is unavailable. The demo uses a timer to simulate an export and an interrupted connection.

A successful job always shows 100% and a ready job shows 0%. Running jobs without a finite progress value show an indeterminate ring. The error state preserves supplied progress and announces Needs attention. Put a useful explanation and a retry action in footer and action.

The summary button supports Enter and Space. Escape inside the details collapses the capsule and returns focus to the summary. Closed details are hidden from assistive technology and inert, so their controls cannot receive focus. Controlled closing also returns focus when it was inside the details.

The progress ring has a progressbar role and remains accessible while collapsed. A separate polite live region announces title and state changes. Percentage updates do not repeat announcements unless you include them in title. Reduced motion disables transitions and spinner rotation.

The expanded capsule grows to 25rem and the collapsed capsule to 20rem, within the available width. Long task names wrap. Colors use your --background, --foreground, --muted-foreground, and --border tokens, with neutral fallbacks. You can override --status-capsule-background, --status-capsule-foreground, --status-capsule-muted, --status-capsule-border, and --status-capsule-highlight through style.