Approval / Permission Request
Preview: Medium
Human-in-the-loop gate: the agent pauses until a person approves or denies a specific action.
Import
import { ApprovalCard } from '@marbleui/ui'Props
<ApprovalCard>
| Prop | Type | Default | Description |
|---|---|---|---|
| onApprove *required | (opts: { remember: boolean; }) => void | — | |
| onDeny *required | () => void | — | |
| risk *required | Risk | — | |
| title *required | ReactNode | — | |
| allowRemember | boolean | true | Offer "Always allow this action". |
| className | string | — | |
| description | ReactNode | — | What exactly will happen. |
| details | { label: string; value: ReactNode; }[] | — | Structured details (recipient, amount, files…). |
| icon | ReactNode | — |
Usage notes
Human-in-the-loop gate: the agent waits for Approve or Deny on one specific action. To confirm an action the user started, use Popconfirm.
<ApprovalCard
title="Send campaign email"
risk="medium"
details={[{ label: 'Recipients', value: '4,812 subscribers' }, { label: 'From', value: 'news@acme.com' }]}
onApprove={({ remember }) => resolveApproval(call.id, { approved: true, remember })}
onDeny={() => resolveApproval(call.id, { approved: false })}
/>
- The card only reports the choice; resuming or skipping the run is up to you. After one press the buttons are replaced by a status line, focus moves to it, and the status region (there from the start) announces the decision. There’s no reset prop, so give each request its own
key. rememberis true when “Always allow” was ticked; storing that rule is your job. The checkbox is hidden forrisk="high"orallowRemember={false}.- Risk is spelled out in the badge text, not only color, and the card is a group labelled “Approval needed:” plus the title (pass a string
titlefor that label).
Example source · show· hide
import { ApprovalCard } from './approval-card'
const I = ({ d }: { d: string }) => (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden><path d={d} /></svg>
)
export const styles = {
Medium: () => (
<ApprovalCard
className="w-[28rem]"
icon={<I d="M4 4h16v16H4zM4 7l8 6 8-6" />}
title="Send campaign email"
description="October product update · Newsletter"
risk="medium"
details={[{ label: 'Recipients', value: '4,812 subscribers' }, { label: 'Send at', value: 'Now' }, { label: 'From', value: 'news@acme.com' }]}
onApprove={() => {}}
onDeny={() => {}}
/>
),
High: () => (
<ApprovalCard
className="w-[28rem]"
icon={<I d="M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6" />}
title="Delete 1,204 inactive accounts"
description="This can’t be undone."
risk="high"
details={[{ label: 'Criteria', value: 'No login in 24 months' }, { label: 'Backup', value: 'Snapshot taken 2 min ago' }]}
onApprove={() => {}}
onDeny={() => {}}
/>
),
}Source: packages/ui/src/approval-card/approval-card.tsx
Catalog
- Category
- ai-agents
- Priority
- Pro
- Primitive
- composed