Skip to main content
NachUI

Tool

A collapsible card for a tool call, with the call's status, its input and what came back.

Input
{
  "locale": "en",
  "limit": 3
}
Output
[
  {
    "slug": "nachui",
    "title": "NachUI",
    "stars": 128
  },
  {
    "slug": "portfolio",
    "title": "ignaciofigueroa.dev",
    "stars": 41
  },
  {
    "slug": "links",
    "title": "links.ignaciofigueroa.dev",
    "stars": 9
  }
]
1'use client';
2
3import { Tool } from '@/components/ui/tool';
4
5const input = { locale: 'en', limit: 3 };
6
7const output = [
8 { slug: 'nachui', title: 'NachUI', stars: 128 },
9 { slug: 'portfolio', title: 'ignaciofigueroa.dev', stars: 41 },
10 { slug: 'links', title: 'links.ignaciofigueroa.dev', stars: 9 },
11];
12
13export function Default() {
14 return (
15 <div className="w-full max-w-md">
16 <Tool status="complete" defaultOpen>
17 <Tool.Header name="get_projects" description="Lists the public projects" />
18 <Tool.Content>
19 <Tool.Input value={input} />
20 <Tool.Output value={output} />
21 </Tool.Content>
22 </Tool>
23 </div>
24 );
25}

Installation

pnpm dlx nachui add tool

Anatomy

1import { Tool } from '@/components/ui/tool';
1<Tool status="complete">
2 <Tool.Header name="get_projects" description="Lists the public projects" />
3 <Tool.Content>
4 <Tool.Input value={{ locale: 'en', limit: 3 }} />
5 <Tool.Output value={projects} />
6 </Tool.Content>
7</Tool>
A tool call starts closed. The name and the status are what the reader needs at a glance; the payloads are there for whoever wants to check them. Pass defaultOpen to the calls worth showing, like a failed one.
Tool.Input and Tool.Output take any value: a string is printed as is, anything else is pretty-printed as JSON. Give Tool.Output children instead when the result deserves real markup.

Composition

Use the following composition to build a Tool:
Tool
├── Tool.Header
└── Tool.Content
├── Tool.Input
└── Tool.Output

Statuses

status lives on the root and drives the indicator in the header: pending waits with a dot, running spins, complete checks off and error flags. Pair error with <Tool.Output error /> so the payload reads as the failure it is.
Input
{
  "to": "contact@ignaciofigueroa.dev",
  "subject": "Hi"
}
Output
422 Unprocessable Entity: recipient domain is not verified
1'use client';
2
3import { Tool } from '@/components/ui/tool';
4
5export function Statuses() {
6 return (
7 <div className="flex w-full max-w-md flex-col gap-3">
8 <Tool status="pending">
9 <Tool.Header name="analyze_job_description" description="Waiting for the previous call" />
10 <Tool.Content>
11 <Tool.Input value={{ body: 'Senior frontend engineer, remote, React and Next.js' }} />
12 </Tool.Content>
13 </Tool>
14 <Tool status="running">
15 <Tool.Header name="get_experience" description="Reading the work history" />
16 <Tool.Content>
17 <Tool.Input value={{ locale: 'en' }} />
18 </Tool.Content>
19 </Tool>
20 <Tool status="complete">
21 <Tool.Header name="get_projects" description="3 projects returned" />
22 <Tool.Content>
23 <Tool.Input value={{ locale: 'en', limit: 3 }} />
24 <Tool.Output value={['nachui', 'portfolio', 'links']} />
25 </Tool.Content>
26 </Tool>
27 <Tool status="error" defaultOpen>
28 <Tool.Header name="send_contact_email" description="The mail provider rejected it" />
29 <Tool.Content>
30 <Tool.Input value={{ to: 'contact@ignaciofigueroa.dev', subject: 'Hi' }} />
31 <Tool.Output error value="422 Unprocessable Entity: recipient domain is not verified" />
32 </Tool.Content>
33 </Tool>
34 </div>
35 );
36}

API Reference

Tool

PropTypeDefaultDescription
status'pending' | 'running' | 'complete' | 'error''complete'State of the call
defaultOpenbooleanfalseOpen state when uncontrolled
openboolean-Controlled open state
onOpenChange(open: boolean) => void-Called when the open state changes
classNamestring-Additional CSS classes

Tool.Header

PropTypeDefaultDescription
namestring-Name of the tool
descriptionstring-One line under the name
statusLabelsPartial<Record<Status, string>>-Screen reader labels for each status
classNamestring-Additional CSS classes

Tool.Content

PropTypeDefaultDescription
classNamestring-Additional CSS classes

Tool.Input

PropTypeDefaultDescription
labelstring'Input'Label above the block
valueunknown-Printed as is when a string, as JSON otherwise
childrenReactNode-Replaces value when given
classNamestring-Additional CSS classes

Tool.Output

PropTypeDefaultDescription
labelstring'Output'Label above the block
valueunknown-Printed as is when a string, as JSON otherwise
errorbooleanfalseDestructive tones for a failed call
childrenReactNode-Replaces value when given
classNamestring-Additional CSS classes
Found something to improve?

Notice a bug, typo, or missing detail on this page? Help us make the documentation better by opening a GitHub issue.

Create an Issue