Inline card that asks the user before an AI agent runs a tool with side effects: the question, the tool name, its arguments as rows, and Approve / Deny buttons that settle into an approved or denied line.
Set your access key from API keys as NEXTUI_TOKEN in .env.local and add the @nextui namespace below to components.json once. Then every item installs by name. Each install counts as a copy on a free account.
$pnpm dlx shadcn@latest add @nextui/tool-approval
1{2"registries": {3"@nextui": {4"url": "https://nextui.dev/r/{name}.json",5"headers": { "Authorization": "Bearer ${NEXTUI_TOKEN}" }6}7}8}
1"use client";23import { useChat } from "@ai-sdk/react";4import { ToolApproval } from "@/components/nextui/tool-approval";56// AI SDK 6: give the tool needsApproval: true on the server, then answer the request here.7export function Messages() {8const { messages, addToolApprovalResponse } = useChat();910return messages.flatMap((message) =>11message.parts.map((part, i) =>12part.type === "tool-send_email" && part.state === "approval-requested" ? (13<ToolApproval14key={i}15title="Send this email?"16toolName="send_email"17details={{ To: part.input.to, Subject: part.input.subject }}18onApprove={() => addToolApprovalResponse({ id: part.approval.id, approved: true })}19onDeny={() => addToolApprovalResponse({ id: part.approval.id, approved: false })}20/>21) : null,22),23);24}
| Prop | Type | Default | Description |
|---|---|---|---|
| title | ReactNode | "Send this email to 3 people?" | The question, in plain words |
| description | ReactNode | – | One line on what happens if the user approves |
| toolName | string | "send_email" | Tool name shown as a chip |
| details | Record<string, ReactNode> | – | Arguments the agent wants to use, shown as label and value rows |
| status | "pending" | "approved" | "denied" | – | Controlled status; leave unset to let the buttons drive it |
| onApprove | () => void | – | Called when the user approves |
| onDeny | () => void | – | Called when the user denies |
| approveLabel | string | "Approve" | Text of the approve button |
| denyLabel | string | "Deny" | Text of the deny button |
| autoPlay | boolean | false | Loop a scripted approval while on screen, for demos |
| className | string | – | Extra classes on the wrapper |
Sign in to see the code
Preview it freely. A free account copies code and prompts a few times a day.