Approval Card

Binary confirmation for agent actions.
npx tool-agent "integrate the approval card component for binary confirmation of agent actions"
npx shadcn@latest add @tool-ui/approval-card

Before the assistant deploys to production, deletes a project, or sends an email on your behalf, it should ask first. ApprovalCard renders a confirmation prompt with context about the action (metadata, consequences, a clear approve/deny choice) and records the decision as a receipt once the user responds.

Role: Decision. For choices that return to the assistant. See Design Guidelines for how component roles work.

Getting Started

Run this once from your project root.

npx tool-agent "integrate the approval card component for binary confirmation of agent actions"
npx shadcn@latest add @tool-ui/approval-card

Render ApprovalCard in your UI with tool-compatible props.

import { ApprovalCard } from "@/components/tool-ui/approval-card";export function Example() {  return (    <ApprovalCard      id="approval-card-example"      title="Deploy to Production?"      description="This will push the latest changes to all users."      icon="Rocket"      confirmLabel="Deploy"      onConfirm={() => console.log("Approved")}      onCancel={() => console.log("Denied")}    />  );}

Register this renderer so tool results display as ApprovalCard.

"use client";import { type Toolkit } from "@assistant-ui/react";import { ApprovalCard } from "@/components/tool-ui/approval-card";import {  safeParseSerializableApprovalCard,  SerializableApprovalCardSchema,} from "@/components/tool-ui/approval-card/schema";export const toolkit: Toolkit = {  requestApproval: {    description: "Request user approval before performing an action.",    parameters: SerializableApprovalCardSchema,    render: ({ args, toolCallId, result, addResult }) => {      const parsedArgs = safeParseSerializableApprovalCard({        ...args,        id: args?.id ?? `approval-${toolCallId}`,      });      if (!parsedArgs) {        return null;      }      return result ? (        <ApprovalCard {...parsedArgs} choice={result} />      ) : (        <ApprovalCard          {...parsedArgs}          onConfirm={() => addResult?.("approved")}          onCancel={() => addResult?.("denied")}        />      );    },  },};

Key Features

Human-in-the-loop

Blocks agent actions until the user approves or denies

Destructive variant

Red styling for irreversible or dangerous operations

Contextual metadata

Key-value pairs giving context about the action

Receipt state

Compact read-only view of the decision in conversation history

Receipt State

Pass a choice prop to render this component in its receipt state. See Receipts for the pattern.

The receipt shows the outcome (approved or denied) with the custom button label you specified, fades in with a subtle animation, and is read-only.

Destructive Variant

Set variant="destructive" for dangerous or irreversible actions. The icon background and confirm button turn red.

Props

Prop

Type

Metadata Schema

Prop

Type

Long metadata values are automatically truncated with an ellipsis. Keep values concise for best results.

Accessibility

  • Uses role="dialog" with aria-labelledby and aria-describedby
  • Keyboard navigation:
    • Tab to move between buttons
    • Enter or Space to activate focused button
    • Escape triggers the cancel action
  • Receipt state uses role="status" for screen reader announcements
  • Fade-in animation respects prefers-reduced-motion