ConsequenceDialog
A dialog that spells out what saying yes will do before anyone confirms.
import { ConsequenceDialog } from "@butteryui/react";Demo
When to use it
Use it for
- Starting a trial, changing a plan or anything that costs money or can't be undone easily
- Confirming after a PlanComparison card's button
Not for
- A plain yes or no: use Dialog with Dialog.Actions
- Asking for values: use FormDialog
Examples
Close a shop
Closing a shop for good, opened from code, the confirm taking a moment while it saves.
Pier Street is open
Plan change
Plan cards that ask first: a card's button spells out what the change will do, and confirming makes it.
Starter
For a roastery selling to its own customers.
Includes
- Online shop
- Subscriptions
Roaster
For a roastery that also sells to cafés.
Everything in Starter, and
- Wholesale accounts
- Price lists
On the Starter plan
Start a trial
A trial that starts only once its cost and timing have been read and confirmed.
On Starter
Variants and states
Starting a trial
What the trial costs and when, the small print, then one button.
Props
ConsequenceDialog
| Prop | Type | Default | Description |
|---|---|---|---|
trigger | ReactNode | The control that opens it, such as a plan's button. Leave it out to open it from code with open. | |
open | boolean | Whether it's open. Pair with onOpenChange to control it. | |
defaultOpen | boolean | false | Whether it starts open when uncontrolled. Defaults to false. |
onOpenChange | ((open: boolean) => void) | Called when it opens or closes. | |
titlerequired | string | What's being confirmed, in title-lg, which names the dialog. | |
itemsrequired | readonly ConsequenceItem[] | What saying yes will do, a row each. | |
terms | ReactNode | Small print under a divider, in caption, links welcome. | |
confirmLabelrequired | string | The confirm button's label, such as "Start the trial". | |
onConfirmrequired | () => void | Promise<void> | Called on the confirm button. It closes once this returns, or once the promise it returns resolves, the button showing busy until then; a rejected promise leaves it open. | |
closeLabel | string | "Close" | Names the close button. Defaults to "Close". |
className | string | Classes for the dialog's content, the element that carries data-bt="ConsequenceDialog". | |
style | CSSProperties | Inline styles for the same element. | |
ref | Ref<HTMLDivElement> | The dialog element. |
ConsequenceItem
One thing that saying yes will do, a row of a `ConsequenceDialog`.
| Field | Type | Default | Description |
|---|---|---|---|
iconrequired | ComponentType<IconComponentProps> | A 16px icon in a 32px tile at the row's start. | |
titlerequired | string | What happens, in title-sm, such as "Then $39 a month". | |
bodyrequired | ReactNode | The detail, in body-sm. |
Accessibility
A modal dialog named by its title. Focus goes to the dialog itself so the consequences are read first; Tab reaches the links in the small print, then the confirm button, which is busy (aria-busy) while a returned promise is pending. Escape or the close button cancels, and focus goes back to what opened it. The rows' icons are decorative.
| Keys | What they do |
|---|---|
| Tab or Shift+Tab | Moves from the dialog itself to the links in the small print, the confirm button and the close button, staying inside |
| Enter or Space | Presses the confirm button, which shows busy while a promise it returned is pending |
| Escape | Cancels and puts focus back on what opened it, unless a confirm is pending |
Motion
It appears with a `Presence` preset and leaves faster than it came, in about 60% of the time.
With reduced motion: It and its scrim fade in and out in 100ms, without growing or rising.
Layout
It's 560px wide at most (--bt-w-dialog-md) and 16px inside the window, scrolling inside when it's taller. Its rows sit 20 apart, each a 32px icon tile beside a heading over a line that wraps, the small print sits under a 1px divider, and the confirm button is full width and 48px tall (--bt-h-cta).
Related
See it in the roastery demo's settings.