Explainable total
A React component in Beamline's Dashboard category.
A total that answers "why this much?" in place: it unfolds into the steps that made it — a waterfall whose bars start where the last step ended, each step with its kind, its reason in real numbers, its source and a thread to the steps it came from; where the host allows, a step's lever (add-on, discount, quantity) re-solves the rest, a pinned version shows what changed, and a re-solved total waits to be applied.
Use it for
- A number with money in it that people question: a quote, an invoice, a refund, a checkout, a commission, a first month's rent.
- The host computes every amount and writes each step's reason; the part presents, threads and animates and never adds money up itself.
Not for
- A KPI with a trend → metric-card.
- A table of many invoices → living-table or data-grid.
Anatomy
- rest: the label, the total (or what's due now of it), Estimate / Not applied when true, Why?
- sheet: the label and Close; the steps; the total row with its bar, the due-now mark and, when pinned, the difference; pin and apply
- step: glyph and kind word, label (lock, set-by chip), a waterfall bar on one shared scale (a soft end for a range, an outline for the pinned version), the amount with its difference; the lever; the reason with its source while read; the host's next-break nudge; parts under it
States
- rest
- open
- pending (the last total readable, dotted, Recalculating…)
- error (no number, Try again)
- unapplied (Apply $…)
- pinned (outlines and differences)
- ineligible step (struck, not counted, with why)
- locked step
- range
Keyboard
- Enter or Space on the total opens it; Escape or Close folds it back with focus on the total
- Tab reaches each step's label (its reason shows and its basis lights) and each lever: switch, slider (arrows), number field (arrows, typing)
- A lever's change announces the new total and the difference
Motion
The total unfolds in place (the shared height morph). A lever's change moves the bars to their new places and rolls the changed digits (slot text); the thread draws between a step and the steps it came from. Reduced motion places at once.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
label (required) | string | — | What the total is: "Quote total", "Refund", "First month". |
steps (required) | TotalStep[] | — | Drawn in this order, each bar starting where the last ended; the host recomputes every amount when a lever moves (a lever may change any step, not only its own). |
total (required) | TotalAmount | — | The host's total; the part never adds money up itself. |
due | number | — | What is due now, when it isn't all of it (a deposit). |
estimate | boolean | — | An estimate says so at rest and in the sheet. |
currency | string | — | |
format | ((amount: number) => string) | — | Money in the host's own format; default: the locale's currency format for `currency`. |
status | "error" | "pending" | "ready" | — | "pending" while the host recalculates (the last total stays readable), "error" when it can't. |
onRetry | (() => void) | — | |
onLeverChange | ((stepId: string, value: number | boolean) => void) | — | |
applied | number | — | The amount actually applied, when a re-solved total is only a suggestion until applied. |
onApply | (() => void | Promise<unknown>) | — | |
pinnable | boolean | — | Offer "Pin this version" to compare against. Default true when any step has a lever. |
open | boolean | — | Controlled open state; omit to use defaultOpen. |
defaultOpen | boolean | — | Initial open state when uncontrolled; defaults to false. |
onOpenChange | ((open: boolean) => void) | — | Reports an open-state change; no callback by default. |
className | string | — | Classes on the documented visual root; no override by default. |
classNames | Partial<Record<"root" | "row" | "total" | "trigger" | "actions" | "bar" | "sheet", stri… | — | Classes for the named visual parts; no overrides by default. |
style | CSSProperties | — | Inline styles on the documented visual root; no overrides by default. |
ref | Ref<HTMLDivElement> | — | Receives the documented native target or imperative handle; omitted by default. |
onLeverCommit | ((stepId: string, value: number | boolean) => void) | — | A lever's settled value: a slider released, a switch flipped, a quantity entered. Recalculate on the server here; `onLeverChange` follows every step for an instant local answer. |
Built from
Used in
Dependencies
lucide-react
Import
import { ExplainableTotal } from "@beamline/explainable-total";
Get it
Explainable total is part of Beamline UI. Install the parts you need in your React app as compiled packages or editable source. Get Beamline · Connect your agent
More in Dashboard
- Explainable change: A metric whose change explains itself: at rest the value, the change against a named period and a thin ribbon of its causes under the change; opened in…
- Budget vessels: Budgets as glasses of money: the liquid is what is left (free money on top, committed money as a lighter layer under it), the lip at the period's budget…
- Insight cards: Findings from an agent, one per page: the sentence, the series it is about with their change, a chart to scrub that names each point, and a follow-up…
- Tracker: A row of status blocks for uptime, job runs or daily checks, with tooltips and a legend.
- Metric card: A KPI that fills its tile: label, a value that rolls to each new number, the change with arrow, sign and tone, what it compares with and the value it…
- Category bar: One bar split into labelled ranges with an optional marker that names its range.
- Bar list: Ranked horizontal bars, label and value over a meter, one line per row when there is room — top pages, sources, customers.
- App shell: The frame for every app screen: collapsible sidebar with grouped navigation, top bar and page.