Chat Tool
Collapsible card that shows an agent's tool call, its input, result, errors and approval step.
Description
ChatTool renders one tool call inside an assistant message. It is a compound component built on Radix Collapsible: a trigger row with a status glyph and the tool name, and a panel holding the input, the result or error, an optional approval step and the call id. Give it toolName, state, input and output and it builds every part for you. Pass children instead and you arrange the slots yourself.
The state prop takes the AI SDK ToolUIPart lifecycle names (input-streaming through output-denied), so part.state goes straight in. In-flight states show a spinner and shimmer the label, attention states tint the frame, and a card with nothing to reveal collapses to a static row. ChatToolGroup folds a batch of calls behind one trigger.
Use it wherever an agent runs functions in a chat: search, retrieval, API calls, file edits, and any action a user has to approve first. Don't use it for the model's reasoning steps. That is Chain of Thought. For a plain "thinking" indicator with no tool attached use Chat Loader, and for files the user attached to a prompt use Chat Attachment.
ChatTool is a Create UI Pro component. Install it with a Pro seat.
Installation
Anatomy
Usage
Examples
Every example is a Pro preview (marked with a Pro badge).
States
Each lifecycle state has its own look. input-streaming, input-available and approval-responded show a neutral spinner and shimmer the label. approval-requested tints the frame with border-warning-weak, output-error with border-error-weak, and output-denied stays neutral with a forbid glyph. Leave state out and the card renders with no status glyph at all.
Streaming input
argsText shows raw text verbatim and wins over input, so partial JSON renders while the model is still writing it. Switch to output once the call resolves. The label keeps the same element through every state, so the shimmer just stops.
Approval
In approval-requested the preset renders Reject and Approve buttons for whichever of onReject and onApprove you pass. Approve is a solid primary button and Reject a neutral outline. Move the card to approval-responded while the agent picks up the answer, then to output-available or output-denied with a denialReason.
Errors
errorText replaces the result in output-error. toolCallId adds a monospace footer, handy when the error needs to be matched against provider logs. An output-error card without errorText renders no empty message row.
Composition
Pass children to skip the preset. ChatTool.StatusIcon still reads state from the root, and a glyph passed as its child replaces the built-in one while keeping the size and tone. ChatTool.Result takes children for a custom result body.
Group
ChatToolGroup collapses several calls behind one trigger. Set active while any call in the batch is still running so the group label shimmers too.
Controlled
open and onOpenChange control the panel from outside, for example to open every card when the user expands a whole conversation. defaultOpen sets the initial state when you don't need control.
Accessibility
When the card has something to reveal, the trigger is a native <button> from Radix Collapsible. Without a body it renders a plain <div>, so there is no dead button in the tab order.
ARIA notes:
- The trigger manages
aria-expandedandaria-controlsthrough Radix. A static row sets neither. - The status glyph, the spinner and the chevron are decorative and marked
aria-hidden, so the state has to be in the label text. UsetriggerPrefix("Failed tool:", "Approval needed:") or say it in your own trigger children. - The shimmer paints the text with a gradient. Under
prefers-reduced-motionand forced colors it stops and the label renders as plain text. The spinner freezes and the panel stops animating under reduced motion too. - With several approval cards on screen, the default "Approve" and "Reject" names repeat. Pass
approveLabelandrejectLabelthat name the action ("Send email") so each button is distinct. - See the Radix Collapsible docs for the full disclosure behavior.
Styling
Tailwind override: className on the root and on every part is merged via cn().
Data slots and attributes: the component sets these for CSS targeting:
data-slot="chat-tool"on the root, withdata-tool-state(the lifecycle state),data-active("true"/"false"),data-expandable("true"/"false") and Radix'sdata-state("open"/"closed").data-slot="chat-tool-trigger"on the trigger row, withdata-expandableand, when it is a button,data-state.data-slot="chat-tool-trigger-label"on the label row, which holds the status glyph and adata-slot="text-shimmer"span withdata-active.data-slot="chat-tool-trigger-prefix"anddata-slot="chat-tool-name"on the preset prefix and tool name.data-slot="chat-tool-status"on the status wrapper, withdata-tool-state. Inside it,data-slot="chat-tool-status-icon"on the glyph, or the spinner's owndata-slot="spinner"while in flight.data-slot="chat-tool-indicator"on the chevron.data-slot="chat-tool-content"on the collapsible panel anddata-slot="chat-tool-content-body"on its padded inner column.data-slot="chat-tool-args",-args-labeland-args-codeon the input block.data-slot="chat-tool-result",-result-labeland-result-codeon the result block.data-slot="chat-tool-error"and-error-labelon the error message.data-slot="chat-tool-denied"and-denied-labelon the denial reason.data-slot="chat-tool-approval",-approval-actions,-approveand-rejecton the approval step.data-slot="chat-tool-meta"on the call id footer.data-slot="chat-tool-group"on the group root, withdata-activeanddata-state.data-slot="chat-tool-group-trigger",-group-trigger-label,-group-indicator,-group-contentand-group-content-bodyon its parts.
States: only the frame and the status glyph change between states.
Motion: the panel uses animate-collapsible-down and animate-collapsible-up, and the chevron rotates over 200ms. Both are skipped under prefers-reduced-motion.
Related Components
- Chain of Thought: use it for the model's reasoning steps, not for function calls.
- Chat Loader: use it for a waiting indicator when there is no tool call to show.
- Accordion: use it for generic expandable sections outside a chat.
- Chat Source: use it to cite the pages a retrieval tool returned inside the answer text.
API Reference
ChatTool
The root card. Wraps Radix's Collapsible.Root, so open, defaultOpen, onOpenChange, disabled and every div attribute pass through. Without children it builds the preset from the props below. Also exported as ChatToolRoot and ChatTool.Root.
Props
Variants
ChatTool.Trigger
The header row. Wraps Radix's Collapsible.Trigger (a <button>) when the card is expandable and renders a static <div> otherwise. ChatTool.StatusIcon children stay outside the shimmer; every other child becomes the truncating label text.
Props
ChatTool.StatusIcon
The status glyph. Extends React.ComponentProps<"span">. Reads state from the root and renders nothing when there is neither a state nor a custom glyph.
Props
ChatTool.Content
The collapsible panel. Wraps Radix's Collapsible.Content and renders nothing on a static card.
Props
ChatTool.Args
The input block. Extends React.ComponentProps<"div"> and renders nothing when there is no text and no children.
Props
ChatTool.Result
The output block. Extends React.ComponentProps<"div">. Hidden in output-error and output-denied, and when there is no value and no children.
Props
ChatTool.Error
The error message in text-error-base. Extends React.ComponentProps<"div"> and renders nothing without errorText or children.
Props
ChatTool.Denied
The denial reason in text-body. Extends React.ComponentProps<"div"> and renders nothing without reason or children.
Props
ChatTool.Approval / ChatTool.ApprovalActions
Approval is the approval step and renders only in approval-requested. ApprovalActions is the right-aligned button row inside it. Both extend React.ComponentProps<"div">.
Props
ChatTool.Approve / ChatTool.Reject
The approval buttons. Both render the registry Button at size="sm" and accept every Button prop, which override the defaults below.
Props
ChatTool.Meta
The monospace call id footer. Extends React.ComponentProps<"div"> and renders nothing without toolCallId or children.
Props
ChatToolGroup
Collapses a batch of calls. Wraps Radix's Collapsible.Root, so open, defaultOpen, onOpenChange and disabled pass through. Parts: ChatToolGroup.Trigger (a Radix Collapsible.Trigger with a truncating label and chevron) and ChatToolGroup.Content (a Radix Collapsible.Content with a padded column). Also exported as ChatToolGroupRoot, ChatToolGroupTrigger and ChatToolGroupContent.
Props
Types
The file also exports the CVA recipes chatToolVariants, chatToolTriggerVariants, chatToolContentVariants, chatToolCodeVariants and chatToolGroupVariants. None of them take variant options.