shadcn.io is not affiliated with official shadcn/ui
Purchase Approval Workflow Billing Block for React
A purchase request for Pro plus 10 seats with an approval chain that grows with the amount: approve as the next person in line, or reject with a reason.
Installation
Overview
Route a spend to the right people before it is billed, with this purchase approval section for React with Base UI. A hairline frame with a plus mark on each corner, ruled by Guides, holds the request at the start (what it is, who asked, a note, the price for the year and a Number Input for the amount, so you can try other sizes) and the approval chain in a side cell. Under $1,000 a manager signs off; up to $10,000 a manager and a director; above that, finance too. Each person in the chain has an Avatar with initials and an outline Badge that says Waiting, Approved, Rejected, Not reached or Not needed, in your foreground color. You act as whoever is next: the Shine Button approves and moves the chain on, and Reject, an outline button, needs a reason written in a Textarea. On a phone the chain sits under the request and the two buttons ride a bar at the foot. For spend management, procurement and any plan that needs a manager's yes.
FAQ
How do I change the request, the people and the thresholds?
Edit APPROVERS (each has a name, initials and title, in the order they sign), the text in the request list, and stepsFor, which turns an amount into how many of them are needed: one under $1,000, two up to $10,000, three above. The rows always show every approver, and the ones the amount does not need say Not needed, so the list never changes height.
What do Approve and Reject do?
You act as the first person who is still waiting. Approve marks them Approved and passes the request to the next. Reject needs a reason in the text box; without one it says so and moves focus there. A rejection marks that person Rejected and the rest Not reached. When the chain is finished, either way, both buttons answer that the request is closed instead of doing anything.
Why does changing the amount start the approvals over?
Because the people who have to sign depend on it. A manager who approved $1,240 has not approved $14,000. The status line says so, and the chain is rebuilt for the new amount. In your app, send an amount change back to the start in the same way.
What stays local, and how do I wire it for real?
Everything. Nobody is notified, nothing is saved and the request is a made-up one on a made-up product. Replace approve and reject with calls to your approvals service, pass the reason with the rejection, and read the chain and each person's state from the server instead of the two numbers in the component.
How does it work with a keyboard and a screen reader?
The current step in the chain carries aria-current="step", every badge is text, and one polite status line reads out who approved, who is next and the end state. A missing reason is announced and focus moves to the box. The amount field has its own name, and the buttons stay focusable when the request is closed so the answer can be heard.