Tool Call
Show an assistant’s tool call, its arguments, status and result.
Installation & usage
npm i @youj/reactFor an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.
Use one for each function, search or API call an assistant makes, inside its Chat Message before the answer. People see that the answer rests on real data, and can open the call to check exactly what went in and came out. For the model thinking without a tool, use Thinking.
import { ChatToolCall } from '@youj/react'
<ChatToolCall
name="get_deployments"
args={{ project: 'orion', limit: 3 }}
status={call.status}
result={call.result}
error={call.error}
duration={call.ms}
/>At rest it's one line: a status mark, the tool's name, a short read of its arguments and a badge. When the result arrives, a two-line preview unfolds under it. Opening the card shows the arguments and the full result, with JSON highlighted. result takes text or anything JSON can show, and duration (in ms) joins the badge once it's done. open, defaultOpen and onOpenChange control the card.
Description
A tool call that moves from queued to running to done, with its result unfolding at the end.
A tool call in each state: pending, running, success and error.
status is pending, running, success or error. The mark is a spinner while it's queued or running, then a check that draws itself in, or a warning that rocks once. The badge reads Queued, Running, Done or Failed, and an error shows error in the preview.
Code
tool-call-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propsname, status, args… (9)
Props
| Prop | Type | |
|---|---|---|
nameRequired | stringThe tool's name, e.g. "get_deployments". | – |
args | Record<string, unknown>Arguments, shown as JSON when opened and summarized in the header. | – |
statusRequired | ChatToolStatus'pending''running''success''error' | – |
result | unknownWhat it returned: text, or anything JSON can show. | – |
error | stringWhy it failed. | – |
duration | numberHow long it ran, in ms. | – |
defaultOpen | boolean | – |
open | boolean | – |
onOpenChange | (open: boolean) => void | – |
Other props pass through: extends ComponentProps<'div'>. | ||
MotionBadge label, badge width, check… · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| Badge labelcrossfades between states (Morph Label) | duration.fastease.standard140ms · cubic-bezier(0.2, 0, 0, 1) | 140mscubic-bezier(0.2, 0, 0, 1) | |
| Badge widththe box morphs to the new label | spring.snappy0.2s, bounce 0 | 0.2s, bounce 0 | |
| Checkdraws itself in on success | duration.slowease.emphasized340ms · cubic-bezier(0.6, 0, 0.1, 1) | 340mscubic-bezier(0.6, 0, 0.1, 1) | |
| Warningrocks once on error | duration.deliberateease.standard560ms · cubic-bezier(0.2, 0, 0, 1) | 560mscubic-bezier(0.2, 0, 0, 1) | |
| Preview unfoldsheight and fade, when the result arrives (Collapse) | duration.baseease.standard220ms · cubic-bezier(0.2, 0, 0, 1) | 220mscubic-bezier(0.2, 0, 0, 1) | |
Open and closethe full exchange (yj-collapse) | duration.baseease.standard220ms · cubic-bezier(0.2, 0, 0, 1) | 220mscubic-bezier(0.2, 0, 0, 1) |
Reduced motion
Every swap and fold is instant, and the marks appear already drawn.
Reduced motion
The badge changes without crossfading, the check and the warning appear without playing, and the preview and the card open and close at once.
AccessibilityKeyboard, announcements
Accessibility
- The header is the card's disclosure button, named by the tool and its status ("get_deployments: Done · 1.5s").
- Each status change is announced once: through the conversation's live regions inside a Chat Message List, or its own status region on its own. Errors are assertive. A call that mounts already settled, as history, isn't announced.
- Long arguments and results scroll inside a named region, which becomes a tab stop once it overflows.