Consequence preview
A React component in Beamline's Actions category.
A risky action that shows what it will do before it runs: one headline sentence, what blocks it and what it also reaches as bands, then the rest as cards with a number each (changes, tells with the people's initials, keeps, can't be undone, not known); with a time dimension the affected items stand as dated tiles and a cut you drag lights them, rippling out from this one, while the counts and the button (named for the result) follow.
Use it for
- Before an action that reaches beyond the row in front of you: reversing a payment, publishing a roster, changing a recurring booking, deleting a segment, recategorising history.
- The host computes the effects (`effects`, `summary`, `confirmLabel`); the part presents them and never invents one.
Not for
- A plain destructive action with nothing beyond its own row → confirm-morph.
- A blocking question that needs the whole screen → alert-dialog.
Anatomy
- trigger: the action's own button when folded
- glance: beside the trigger when folded, the kinds it reaches with their counts; the trigger is described by it
- sheet (unfolded in place, or open from the start): the sentence as the headline, focused when a person opens it and read once; live afterwards only when there is no strip
- bands across the sheet: blocked by (an ordered chain, each step with its action), also reaches (the warning tone)
- time strip (optional): a dated tile per item (past dimmer, locked hatched with a lock), the selected tile ringed, now marked, the cut in the gap after the last tile in scope, snap words (This one · From here on · All, history too); on a narrow room the tiles keep their light and the dates move to the ends
- cards: per kind the word and glyph, the count large, the label, up to three named examples with "and N more"; the people a kind tells as initials beside their names
- actions: Cancel and the result-named confirm; the reason when it waits
- receipt: the result, View before, Undo with its time left
States
- rest (button and glance)
- open
- loading (rows keep their shape, confirm waits)
- error (blocked, Try again)
- blocked (confirm disabled with the reason)
- working
- done (receipt with Undo)
- failed (said, Try again)
- undo refused (said on the receipt; Undo stays)
Keyboard
- Enter or Space on the trigger opens; focus moves to the sentence
- Tab through the rows' actions, the strip and the buttons
- On the strip: ←/→ between This one, From here on and All; Shift+←/→ one item at a time; Home/End to All and From here on
- Escape folds the sheet back with nothing changed; focus returns to the trigger
Motion
The button unfolds in place into the sheet (the shared height morph) and folds back into the receipt. Moving the cut lights the tiles in scope with a ripple out from this one (a step per tile away from it); while the strip is held the lighting follows the hand with no ripple. A card whose count changed rises into its new number once. Reduced motion places at once.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
label (required) | ReactNode | — | The action at rest: "Publish roster", "Reverse payment". |
icon | ReactNode | — | |
tone | "danger" | "neutral" | — | Danger for a destructive action, neutral otherwise. Default "danger". |
effects | ConsequenceEffect[] | — | The effects, by kind, for the current scope. Recompute them in `onScopeChange`. |
status | ConsequenceStatus | — | Whether the host is still computing the effects ("loading"), has them ("ready") or could not ("error"). A loading or failed check never offers the confirm button. Default "ready". |
summary | ReactNode | — | One plain sentence written from the effects: "Changes 24 shifts for 9 people and notifies them tonight." |
confirmLabel (required) | string | — | The confirm button's words: the result, never "OK": "Publish 24 shifts, notify 9 people". |
onConfirm | (() => void | Promise<unknown>) | — | Runs the action; return a promise and the button shows working until it settles. |
onRetry | (() => void) | — | Called by "Try again" after a failed check. |
strip | ConsequenceStrip | — | A time dimension: the items the action could reach, as a strip with a cut. |
scope | ConsequenceScope | — | Controlled scope; omit to use defaultScope. |
defaultScope | ConsequenceScope | — | Initial scope when uncontrolled. Default "one" (the selected item alone). |
onScopeChange | ((scope: ConsequenceScope) => void) | — | Reports the scope as the cut moves, for an instant local answer. |
receipt | string | — | The receipt after the action: "Published 24 shifts". Default the confirm label. |
undoFor | number | — | Seconds the receipt offers Undo; 0 offers none. Default 600. |
onUndo | (() => void | Promise<unknown>) | — | |
onViewBefore | (() => void) | — | Opens the record as it was before the action ("View before" on the receipt). |
open | boolean | — | Whether the sheet is open; 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. |
disabled | boolean | — | |
className | string | — | Classes on the documented visual root; no override by default. |
classNames | ConsequencePreviewClassNames | — | 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. |
onScopeCommit | ((scope: ConsequenceScope) => void) | — | The scope settled: a drag released, a key, a snap, a tap. Recompute effects on the server here. |
Built from
Used in
Dependencies
lucide-react
Import
import { ConsequencePreview } from "@beamline/consequence-preview";
Get it
Consequence preview 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 Actions
- Theme switch: The light/dark control: the page changes in one of four transitions starting from the button (reveal, eclipse, split, rise), and the icon turns between…
- Confirm morph: A destructive action that asks in place: the button morphs into its question, then into working, then into the result with Undo or Retry, without a dialog.
- Swipe actions: Row actions behind a swipe on touch screens and a two-finger swipe on a trackpad, and at the row's end for pointer and keyboard (a ⋯ menu in a narrow…
- Hold to confirm: Confirms a costly action by holding instead of clicking: a fill sweeps across while held and drains if let go early; pointer, touch, Space and Enter all…
- Split button: One obvious action joined to a menu of close alternatives; both halves are real buttons and the menu uses the shared menu rows.
- Copy button: Copies a value and confirms in place: the icon becomes a check and the label says Copied; a refused copy says so instead of pretending.
- Button: The action control: five weights and a brand fill, a buy/sell tone, sm/md/lg and a 44 px touch size, icon-only, a loading state that keeps its size and…