ComponentsFlows & wizards

Approval flow

Shows and acts on a multi-stage approval: sequential and parallel stages ("all of" / "any of"), approvers with decisions, timestamps and comments, rule conditions, SLA deadlines and delegation. ApprovalActions confirms each decision in a dialog with a note; ApprovalSummary is the one-line status for table rows.

Avatar · Badge · Dialog · Select business/approval-flow.tsxtheme · material · accent · density · font
  1. Submitted by Deniz Aydın

    Annual leave, 17–28 November (10 working days).
  2. Manager approval

    Approved

    1 approver

    • Ayşe YılmazEngineering manager

      approved

      Fine by me — Mert covers the on-call week.
  3. HR review

    In review

    Any one of 2 approversDue in 2 days

    • Selin ArslanPeople partner

      Pending

    • Burak KoçPeople operations

      Pending

  4. Payroll update

    Waiting

    1 approver

    • Gizem ErPayroll

      —

Installation

$ pnpm add @vamos-ui/react

The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";

Usage

import { ApprovalFlow, ApprovalActions, ApprovalSummary } from "@vamos-ui/react/business";

<ApprovalFlow requester={{ name: "Deniz Aydın", at: request.createdAt }} stages={request.stages} />
<ApprovalActions canAct={me.isApprover} onApprove={approve} onReject={reject} onRequestChanges={sendBack} />
<ApprovalSummary stages={row.stages} />  // "2 of 3 approved · Now: Finance"

The flow is an <ol>; parallel stages are a nested list named "In parallel". Status is always text (badge + decision words), never colour alone. A visual flow designer is out of scope: the server defines stages, this renders and acts on them.

Examples

Parallel branches

Consecutive stages with the same parallelGroup render side by side. Each says "Any one of 2 approvers" or "All of 3 approvers"; delegated decisions carry a badge.

  1. In parallel

    1. Finance

      Approved

      Any one of 2 approvers

      • Kerem Demir

        approved

      • Elif Şahin

        —

    2. Legal

      In review

      All of 3 approversDue tomorrow

      • Zeynep Kaya

        approved

        Liability cap is acceptable.
      • Oliver GrantExternal counsel Delegated

        approved · on behalf of Hannah Weiss

      • Mehmet Uçar

        Pending

  2. CEO signature

    Waiting

    1 approver

    • Can Öztürk

      —

Conditions and changes requested

A Director stage added by a rule ("Amount > $10,000") sent the request back; later stages are skipped.

  1. Submitted by Jonas Fischer

  2. Budget owner

    Approved

    1 approver

    • Nora Lindqvist

      approved

  3. Director

    Changes requested

    1 approverOnly when Amount > $10,000

    • Rafael Duarte

      requested changes

      Please attach the second supplier quote before I sign this.
  4. Finance

    Skipped

    1 approver

    • Priya Raman

      —

Approve, reject, request changes, delegate

Reject and Request changes require a note (requireNoteOn); the dialog focuses it. Results are announced politely.

Quote Q-2026-207 · Northwind Traders

18% discount on 120 seats — requested by Pınar Güneş

  1. Sales manager

    In review

    1 approverOnly when Discount > 15%

    • YouSales manager

      Pending

  2. CFO

    Waiting

    1 approverOnly when Discount > 25%

    • Hana Kobayashi

      —

In a table row

ApprovalSummary: one dot per stage plus "2 of 3 approved" — expense and leave lists.

ExpenseEmployeeAmountApproval
EXP-2041Client dinner, IzmirAyla Çelik$412.801 of 3 approved · Now: Finance
EXP-2040Flights IST → LHRBen Hartley$1,284.003 of 3 approved
EXP-2038Conference ticketFarah Jansen$899.00Rejected
EXP-2035Taxi, airport transferOmar Ekström$64.20Changes requested

API

ApprovalFlow

PropTypeDefault
stages
{ id, title, mode: "all" | "any", condition?, approvers[], status, dueAt?, parallelGroup? }. Status: waiting · active · approved · rejected · changes_requested · skipped · withdrawn.
ApprovalStageData[]—
requester
First node: who submitted, when and why.
{ name; avatarUrl?; at; note? }—
orientation
Horizontal lays stages out in a scrollable row.
"vertical" | "horizontal""vertical"
variant
compact renders ApprovalSummary.
"full" | "compact""full"
now
Reference time for SLA (pass it for SSR-stable output).
string | numberDate.now()
labels
Statuses, mode texts (plural-aware), SLA, actions.
Partial<ApprovalFlowLabels>—

ApprovalApprover / ApprovalDecision

PropTypeDefault
approver
One person on a stage.
{ id; name; avatarUrl?; role?; decision? }—
decision
UTC ISO instant; the note renders as a comment.
{ value: "approved" | "rejected" | "changes_requested"; at; note?; delegatedFrom? }—

ApprovalActions

PropTypeDefault
canAct
When false, shows cantActReason instead of buttons.
boolean—
onApprove
Approve with an optional note.
(note?: string) => Promise<void> | void—
onReject
Reject; a note is required by default.
(note: string) => Promise<void> | void—
onRequestChanges
Shows "Request changes".
(note: string) => Promise<void> | void—
onDelegate / delegates
Shows "Delegate" with a person Select.
(to, note?) => … / { id; name }[]—
requireNoteOn
Which actions need a note.
("approve" | "reject" | "changes")[]["reject", "changes"]
cantActReason
Text for viewers who can't act.
string—
size
Button size.
"sm" | "md""md"

ApprovalSummary

PropTypeDefault
stages
Same data as the flow.
ApprovalStageData[]—
showCurrent
Append "Now: {stage}".
booleantrue