Approval

A card asking to allow a tool call, with its arguments and answer buttons.

View as Markdown
Send mail
To
alex@acme.comsam@acme.com
Subject
Q3 forecast, revised

Hi both, the revised forecast is attached. Revenue holds at 4.2M; the change is in hiring, pushed to October. Shout if anything looks off before Thursday’s review.

<Approval>  <ApprovalHeader>    <ApprovalTitle>      <ApprovalMedia>        <HugeiconsIcon icon={Mail01Icon} />      </ApprovalMedia>      Send mail    </ApprovalTitle>  </ApprovalHeader>  <ApprovalContent>    <ApprovalFields>      <ApprovalField>        <ApprovalFieldLabel>To</ApprovalFieldLabel>        <ApprovalFieldValue>          <Badge variant="secondary">alex@acme.com</Badge>          <Badge variant="secondary">sam@acme.com</Badge>        </ApprovalFieldValue>      </ApprovalField>      <ApprovalField>        <ApprovalFieldLabel>Subject</ApprovalFieldLabel>        <ApprovalFieldValue>Q3 forecast, revised</ApprovalFieldValue>      </ApprovalField>    </ApprovalFields>  </ApprovalContent>  <Separator />  <ApprovalContent>    <p>Hi both, the revised forecast is attached.</p>  </ApprovalContent>  <ApprovalFooter>    <ApprovalCancel>Cancel</ApprovalCancel>    <Button size="sm" variant="primary">      Send mail    </Button>  </ApprovalFooter></Approval>

Installation

$ npx shadcn@latest add @constella/approval

Usage

import {  Approval,  ApprovalAction,  ApprovalCancel,  ApprovalContent,  ApprovalField,  ApprovalFieldLabel,  ApprovalFields,  ApprovalFieldValue,  ApprovalFooter,  ApprovalHeader,  ApprovalMedia,  ApprovalTitle,} from "@/components/ai/approval";
<Approval>  <ApprovalHeader>    <ApprovalTitle>Delete file</ApprovalTitle>  </ApprovalHeader>  <ApprovalFooter>    <ApprovalCancel>Cancel</ApprovalCancel>    <Button size="sm" color="danger">      Delete file    </Button>  </ApprovalFooter></Approval>

Composition

Approval├── ApprovalHeader│   ├── ApprovalTitle│   │   └── ApprovalMedia│   └── ApprovalAction├── ApprovalContent│   └── ApprovalFields│       └── ApprovalField│           ├── ApprovalFieldLabel│           └── ApprovalFieldValue└── ApprovalFooter    └── ApprovalCancel

Name the confirm button for the action ("Send mail"), never "Approve". ApprovalCancel sits alone at the footer's start, the action at its end, so a slip lands on the button that does nothing. Another option, such as Edit, goes just before the action.

Busy

While the call resumes, disable both buttons and set aria-busy on the one pressed.

Approval Action

Once answered, drop the footer and say what happened in a Badge in ApprovalAction.

Send mail
Sent
To
alex@acme.comsam@acme.com
Subject
Q3 forecast, revised
Reply to mail
Cancelled
To
Everyone on the thread
<ApprovalHeader>  <ApprovalTitle>Send mail</ApprovalTitle>  <ApprovalAction>    <Badge color="success" variant="secondary">      Sent    </Badge>  </ApprovalAction></ApprovalHeader>
MomentFooterAction
AskingCancel apart, the actionNone
ResumingBoth disabledNone
AnsweredNoneA Badge: what happened

API Reference

PartAdds
ApprovalA sm Card with role="group", named by its title
ApprovalTitleThe card's name; a row with the media before the text
ApprovalMediaThe tool's bare icon, centered on the title's line and hidden from screen readers
ApprovalFieldsA dl grid: labels in textSecondary, values wrap anywhere
ApprovalFooterThe card's footer, buttons at its end
ApprovalCancelAn outline sm Button, pushed to the footer's start

ApprovalHeader, ApprovalAction and ApprovalContent are the Card's parts. Every part takes sx, applied last. ApprovalField renders a div, its label a dt and its value a dd.