All components (244)
Approval chain
Management · ApprovalFlow
What it is and when to use it
An approval chain: the steps in order, who has to decide in each one, what they decided and when, and with what note.
When to use it
- Approving an expense, a holiday, a contract or a publication that goes through several people.
stepsare the steps and each carries itsapproverswith their decision (pending,approved,rejected,skipped).mode="any"makes one enough; by default everyone approves.- The first pending step is the current one and the following ones wait. A single rejection rejects the whole.
- With
currentUserIdandonDecide, whoever has the decision pending in the current step sees "Approve" and "Reject"; rejecting asks for a reason (requireReason).
When not to
- A step wizard for a form:
Wizard. - The component does not change
steps: it callsonDecideand the application changes it. The server has to check again that the person can decide.
Keyboard: they are normal buttons and a text field; the current step carries aria-current="step".
Accessibility: the state of each step and the decision of each person are written out, so colour is not the only thing that informs. Each decision is announced, and if it fails it is said in an alert.
Fine appearance: each step is a box with a stripe on the left: accent for the current one, success for the approved one, error for the rejected one.
What it looks like
In progress1 of 2 steps approved
Step 1Purchasing managerApproved
- Marta Ruiz Approved
It fits the budget.
- Marta Ruiz Approved
Step 2AddressTheir turn
- Aitor Mena Pending
- Carla Gil Pending
<ApprovalFlow
label="€4,200 purchase of materials"
steps={pasos}
currentUserId="aitor"
requireReason
onDecide={(paso, decision, comentario) => guardarDecision(paso, decision, comentario)}
/>Props
Import it with import { ApprovalFlow } from '@amset/ui'. Required props are marked.
| Prop | Type | What it does |
|---|---|---|
labelrequired | string | What is being approved («Approval of expense 2026-114»). Required. |
stepsrequired | readonly ApprovalStep[] | — |
className | string | Merged with the library classes; it does not replace them. |
currentUserId | string | Who is looking: if it is their turn to decide in the current step, their buttons appear. Without this it is read-only. |
onDecide | (stepId: string, decision: ApprovalDecision, comment: string) => void | Promise<void> | Record the decision of `currentUserId` in a step. If it throws or rejects, it says so and the buttons stay where they were. The library does not change `steps`: the application does, and the server has to check that the person can decide. |
requireReason | boolean | Require a reason to reject. On by default. |
It also accepts the attributes of the element it renders: className, style, data-*, aria-* and its events.
In the test bench
Every state and variant, to try one at a time, on its page at ui.amset.tech:
