Prodular UI

Approval

AIPro

Human in the loop: an agent asks to perform an action and a person approves, edits or rejects it, with what, why, affected items, parameters and risk in view.

npx prodular-ui add approval

Part of Prodular UI Pro. Preview and read the docs freely, install with a license. See pricing

Inline request

Approve, or reject with a reason the agent reads before it tries again. The actions turn into a record of who decided and when.

Collections agent requests approval · 2 min ago

Send 14 payment reminders

Medium risk

These invoices are more than 30 days past due and have had no reply to the first notice. Each customer gets the second notice template with the invoice attached.

Recipients$38,920.00 outstanding
  • Northwind StudioINV-2041, 42 days$4,180.00
  • Halcyon FreightINV-2017, 38 days$7,950.00
  • Brightwater DentalINV-1996, 61 days$2,310.00
  • Okafor & LaneINV-2052, 33 days$1,640.00

and 10 more

What will be sent
Template
Second notice, friendly
From
ar@ledgerline.app
Send at
Today, 15:00 in each customer's time zone
Batch id
rmd_2026_10_21_a7f3

In a dialog

For high risk actions that should interrupt. Pass variant="dialog" and give DialogContent p-0.

Waiting for a decision

Resolved states

Approved, rejected with a reason, and expired.

Dispatch agent requests approval · 09:41

Move 3 visits to Thursday

Low risk
Approved by Maya Chen at 14:02
Billing agent requests approval · 11:15

Write off $6,400.00 for Halcyon Freight

High risk
Rejected by Daniel Okafor at 11:32

They agreed to a payment plan on the call. Set up three monthly installments instead.

Collections agent requests approval · yesterday

Pause the account for Brightwater Dental

Medium risk
Expired

Nobody decided within 24 hours, so nothing changed.

Anatomy

<Approval status="pending" risk="medium">  <ApprovalHeader>    <ApprovalRequester agent="Collections agent" time="2 min ago" />    <ApprovalTitle>Send 14 payment reminders</ApprovalTitle>    <ApprovalRisk />    <ApprovalDescription>Why the agent wants to do this.</ApprovalDescription>  </ApprovalHeader>  <ApprovalSection title="Recipients">    <ApprovalItems total={14}>      <ApprovalItem title="Northwind Studio" description="INV-2041" value="$4,180.00" />    </ApprovalItems>  </ApprovalSection>  <ApprovalSection title="What will be sent">    <ApprovalParams>      <ApprovalParam label="Template">Second notice</ApprovalParam>    </ApprovalParams>  </ApprovalSection>  <ApprovalActions>    <Button>Approve and send</Button>    <Button variant="outline">Edit</Button>    <Button variant="ghost">Reject</Button>  </ApprovalActions></Approval>

Guidance

Use it when

  • Use it before any action an agent takes that leaves the product, moves money, changes many records or cannot be undone.
  • Title the request as the action with its number and object: Send 14 payment reminders, Refund $1,240.00 to Northwind Studio.
  • Explain why in ApprovalDescription with the evidence the agent used, in one or two sentences.
  • Show the affected items with ApprovalItems and pass total so people know how many are hidden. Show exactly what will be sent or changed in ApprovalParams.
  • Use the inline variant inside an agent run, a thread or a review queue. Use the dialog variant for a single high risk request that should interrupt.

Avoid

  • Vague titles such as Approve action or Agent request.
  • Hiding the amount, the recipient count or the irreversibility in a collapsed section.
  • Approve buttons that only say Approve when the action has a clear verb. Say Approve and send, Approve refund.
  • Removing the request after it is decided. Keep it with ApprovalResolution so there is a record.

Rules for AI agents

Published in llms-full.txt, the registry and the MCP server, so coding agents follow them when they build with this component.

  • Route every irreversible, external or financial action through an Approval and wait for an explicit approve event before executing it. Never execute on render, on timeout or on dismiss.
  • Always set risk. Use high for anything irreversible or involving money leaving the account, medium for messages to customers or bulk changes, low for reversible internal changes.
  • The title must include the verb, the count or amount, and the target. Include currency symbols and two decimals for money.
  • Render three actions in this order: the primary approve button labelled with the verb, an outline Edit that opens the parameters, and Reject. For high risk in a dialog, the approve button uses variant="destructive".
  • When rejected, ask for a reason and pass it back to the agent. Show it in ApprovalResolution with the person's name and the time.
  • After a decision, set status to approved, rejected or expired and replace ApprovalActions with ApprovalResolution. Never leave buttons active on a decided request.
  • In a dialog, render ApprovalTitle with render={<DialogTitle />} so the dialog has an accessible name, and give DialogContent className="gap-0 p-0".

API

Approval

PropTypeDefaultDescription
status"pending" | "approved" | "rejected" | "expired""pending"Exposed as data-status. ApprovalResolution reads it.
risk"low" | "medium" | "high"Exposed as data-risk. ApprovalRisk reads it.
variant"inline" | "dialog""inline"inline is a card. dialog drops the chrome to sit in DialogContent with p-0.

ApprovalRequester

PropTypeDefaultDescription
agentstringName of the agent asking, shown with the AI mark.
timestringWhen it asked.

ApprovalTitle

PropTypeDefaultDescription
renderReactElementRender as DialogTitle inside a dialog.

ApprovalRisk

PropTypeDefaultDescription
level"low" | "medium" | "high"Defaults to the risk on Approval. Children replace the label.

ApprovalItems

PropTypeDefaultDescription
totalnumberTotal affected items. Adds an and N more line.

ApprovalItem

PropTypeDefaultDescription
title / description / valueReactNodeName, detail and a right aligned amount.

ApprovalParam

PropTypeDefaultDescription
labelReactNodeThe parameter name. Set mono for ids and raw values.

ApprovalResolution

PropTypeDefaultDescription
by / at / reasonstring / string / ReactNodeWho decided, when, and why for rejections.

Installation

The Prodular UI CLI adds the source to components/ui with everything it depends on. In a project that already uses shadcn/ui, the shadcn CLI installs it from the Prodular registry too. See Installation for the first setup.

npx prodular-ui add approval# or, with the registry in components.jsonnpx shadcn@latest add @prodular/approval