AI Interface Components

AI Tool Call Card

A status card for an AI tool call that transitions smoothly between running / success / error, and expands to show the arguments and result.

This is a WebberUI Pro component

The install command below needs a licence to run; without one it returns 401.

How to install Pro components →See the plans →

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 "https://webberui.com/r/ai-tool-call-card.en.json?t=<install token>"

New project or installation trouble? Start here →

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

1240
Active edited usageDefault props
<AiToolCallCard/>

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/ai-tool-call-card.en.json?t=<install token>"

Or, once registries are configured in components.json, install it as @webberui/ai-tool-call-card.

Usage

import { AiToolCallCard } from "@/components/ui/ai-tool-call-card";

<AiToolCallCard
  name="search_web"
  status="running"
  description="Search the document library to answer the user's question"
  args={{ query: "webber ui motion", top_k: 5 }}
/>;

status is driven by your agent's execution flow, and the card transitions automatically as the value changes: the circular indicator's icon pops in, the status text flips vertically, and the border color tints smoothly.

Status transitions

Just bind status to the tool call's real lifecycle and the component handles every transition animation:

const [status, setStatus] = useState<ToolCallStatus>("pending");

async function call() {
  setStatus("running");
  try {
    const result = await runTool();
    setStatus("success");
  } catch {
    setStatus("error");
  }
}

On entering error, uncontrolled mode expands automatically to reveal the error message.

Expanding the arguments and result

The card can expand when args is provided; result (on success) and error (on failure) are shown in their respective sections. The expanded state supports controlled and uncontrolled modes:

<AiToolCallCard
  name="run_sql"
  status="success"
  args={{ table: "orders", limit: 100 }}
  result={<pre>{JSON.stringify(rows, null, 2)}</pre>}
  expanded={open}
  onExpandedChange={setOpen}
/>

Props

PropTypeDefaultDescription
namestring—Tool (function) name, shown in a monospace face
status"pending" | "running" | "success" | "error"—The current status; changing it triggers the transition animation
labelstringPer statusOverrides the status text on the right
descriptionstring—A one-line subtitle beneath the name
argsRecord<string, unknown>—Call arguments, shown as a monospace key/value list
resultReact.ReactNode—Shown in the "Result" section on success
errorReact.ReactNode—Shown in the "Error" section on failure
elapsedMsnumber—Elapsed time (ms), formatted next to the status text
expandedboolean—Controlled expanded state
defaultExpandedbooleanfalseInitial expanded state in uncontrolled mode
onExpandedChange(expanded: boolean) => void—Callback when the expanded state changes

How it works

  • The circular indicator swaps icons by status through AnimatePresence: the old icon shrinks away and the new one springs in
  • The status text uses a flip window (an overflow mask), with the old value flipping out upward and the new one flipping in from below
  • The border and the indicator's base color tint smoothly via transition-colors (var(--wb-duration-normal,300ms))
  • While running, an indeterminate bright band sweeps along the bottom line, signalling that the tool is still working
  • The expandable area opens and closes with a height: auto transition, and the content fades in

Accessibility

  • The card contains plain text with role="status" and aria-live="polite", announcing "name: status" whenever the status changes
  • Every animated node is aria-hidden, so nothing is announced twice
  • When expandable, the header row is a <button> carrying aria-expanded / aria-controls, supporting keyboard operation and a focus ring
  • When the user has "reduce motion" enabled: the indicator stops spinning, the flip becomes a fade in / fade out, the progress band is hidden, and expanding switches instantly — while the DOM structure stays consistent (the switch happens only after mount, avoiding a hydration mismatch)