ToolCall
freeToolCall exposes a tool invocation with running, completed, and failed states plus formatted input and output details.
motionreact-iconsshiki
Preview
Dark
import ToolCall from '@/components/composites/ToolCall';
export default function UsageDemo() {
return (
<div className="w-full max-w-xl">
<ToolCall
name="getWeather"
state="output-available"
input={{ city: 'Singapore' }}
output={{ temperature: 31, unit: 'C', condition: 'Cloudy' }}
/>
</div>
);
}States
Preview
Dark
Input
{
"city": "Singapore"
}Error
The weather provider did not return a result.
import ToolCall from '@/components/composites/ToolCall';
export default function StatesDemo() {
return (
<div className="w-full max-w-xl space-y-3">
<ToolCall
name="getWeather"
state="input-streaming"
input={{ city: 'Singapore' }}
/>
<ToolCall
name="getWeather"
state="input-available"
input={{ city: 'Singapore' }}
/>
<ToolCall
name="getWeather"
state="output-error"
input={{ city: 'Singapore' }}
errorText="The weather provider did not return a result."
/>
</div>
);
}Custom Result
Pass children when the tool output needs a product-specific renderer. This example treats the output as a completed web search: a nested SearchResult disclosure owns the query header, result count, collapse affordance, and source rows instead of the default JSON block.
Preview
Dark
import { PiCaretDown, PiSparkle } from 'react-icons/pi'
import Collapsible from '@/components/ui/Collapsible';
import ToolCall from '@/components/composites/ToolCall';
const results = [
{
title: 'Extended thinking - Claude Platform Docs',
domain: 'platform.claude.com',
url: 'https://platform.claude.com/docs/en/build-with-claude/extended-thinking',
favicon: '/img/thumbs/brands/claude.png',
},
{
title: 'Building with Claude Extended Thinking | by Cobus Greyling | Medium',
domain: 'medium.com',
url: 'https://cobusgreyling.medium.com/building-with-claude-extended-thinking-d1a8b3130834',
favicon: '/img/thumbs/brands/medium.png',
},
{
title: 'Claude on X',
domain: 'x.com',
url: 'https://x.com/claudeai',
favicon: '/img/thumbs/brands/x.png',
},
{
title: 'Extended thinking examples - Anthropic Cookbook',
domain: 'github.com',
url: 'https://github.com/anthropics/anthropic-cookbook/',
favicon: '/img/thumbs/brands/github.png',
},
];
type SearchResultProps = {
query: string;
resultCount: number;
results: typeof results;
};
function SearchResult({ query, resultCount, results }: SearchResultProps) {
return (
<Collapsible
defaultOpen
className="w-full overflow-hidden rounded-card border bg-card"
>
<Collapsible.Trigger>
{({ isOpen, toggle }) => (
<button
type="button"
aria-expanded={isOpen}
className="flex w-full items-center gap-2 py-2 px-4 text-left text-foreground transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset "
onClick={toggle}
>
<PiSparkle
aria-hidden="true"
className="size-4 shrink-0"
/>
<span className="min-w-0 flex-1 truncate text-sm">{query}</span>
<span className="flex shrink-0 items-center gap-1 text-muted-foreground text-xs">
<span>{resultCount} results</span>
<PiCaretDown
aria-hidden="true"
className={`size-4 transition-transform ${isOpen ? 'rotate-180' : ''}`}
/>
</span>
</button>
)}
</Collapsible.Trigger>
<Collapsible.Content className="overflow-visible">
<div className="space-y-1 pb-2 px-2" role="list">
{results.map((result) => (
<a
className="flex items-center gap-2 rounded-control-sm px-2 py-2 transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset"
key={result.title}
href={result.url}
target="_blank"
rel="noreferrer"
role="listitem"
>
<img
src={result.favicon}
alt=""
aria-hidden="true"
className="size-4 shrink-0 object-contain"
/>
<span className="min-w-0 flex-1 truncate text-foreground text-sm">
{result.title}
</span>
<span className="shrink-0 text-muted-foreground text-xs">
{result.domain}
</span>
</a>
))}
</div>
</Collapsible.Content>
</Collapsible>
);
}
export default function CustomResultDemo() {
return (
<div className="w-full max-w-xl">
<ToolCall
name="webSearch"
state="output-available"
input={{ query: 'Extended thinking UI component design' }}
>
<SearchResult
query="Claude.ai extended thinking UI component design"
resultCount={9}
results={results}
/>
</ToolCall>
</div>
);
}API
ToolCall
| Prop | Description | Type | Default |
|---|---|---|---|
name | Tool name shown in the trigger row. | string | — |
state | Current invocation state. | ToolCallState | — |
input | Invocation input rendered as formatted JSON. | unknown | — |
output | Invocation output rendered as formatted JSON. | unknown | — |
errorText | Error content rendered in the error state. | string | — |
children | Custom result renderer replacing the output JSON block. | ReactNode | — |
className | Classes merged onto the disclosure root. | string | — |
ToolCallState
type ToolCallState =
| 'input-streaming'
| 'input-available'
| 'output-available'
| 'output-error';