Confirm dialog

Asks one question before an action that can't be undone, such as deleting an API key.

Live React portVue source: WildConfirmDialog.vueReact component: WConfirmDialog

Try it

Set the label to OK to see how little the button says. Press Delete key to reopen it.

Delete this API key?
It is removed permanently.
Confirm label
Tone
Consequence
<WConfirmDialog
  open={open}
  title="Delete this API key?"
  confirmLabel="Delete key"
  onConfirm={deleteKey}
  onCancel={() => setOpen(false)}
>
  It is removed permanently.
</WConfirmDialog>

When to use

  • Use it before an action that deletes data or can’t be undone.
  • Use it when an action affects more than the thing in front of the person, such as anything that uses an API key.
  • Use it, in the primary tone, before a reversible action with wide effects, such as pausing an automation.
Don’t use it
  • For routine actions that are quick to undo. Run them, and confirm with a toast.
  • To collect input or show a form. Use Dialog.

Variants

Destructive is the default. Use primary when nothing is lost but the effect is wide, such as pausing an automation. Add a consequence panel when the action reaches beyond the thing itself.

<WConfirmDialog
  open={open}
  title="Cancel this invite?"
  confirmLabel="Cancel invite"
  cancelLabel="Keep invite"
  onConfirm={cancelInvite}
  onCancel={() => setOpen(false)}
>
  It is removed permanently.
</WConfirmDialog>
The confirm sits on the right, where the primary always sits. Cancel can name what it keeps.
<WConfirmDialog
  open={open}
  title="Delete this API key?"
  confirmLabel="Delete key"
  consequence="Anything using this key can no longer reach the API."
  onConfirm={deleteKey}
  onCancel={() => setOpen(false)}
>
  It is removed permanently.
</WConfirmDialog>
<WConfirmDialog
  open={open}
  title="Pause this automation?"
  confirmLabel="Pause automation"
  tone="primary"
  onConfirm={pauseAutomation}
  onCancel={() => setOpen(false)}
>
  It stops running until you turn it back on.
</WConfirmDialog>

Content

  • Ask the question in the title, naming the thing: “Delete this API key?”
  • Say in the body what is lost and what isn’t.
  • Name the consequence on the button: “Delete key”, “Cancel invite”. People who skim the body still read the button.
  • Name what else breaks in the consequence panel, with a number where there is one.
  • Name what Cancel keeps when “Cancel” would be ambiguous: “Keep invite”.
Don’t use it
  • OK, Yes or Confirm on the button. They don’t say what happens.

Accessibility

It opens as an alert dialog, named by its title and described by its body and consequence. Focus lands on Cancel, so a double Enter can’t delete anything, and returns to the trigger on close.

KeyWhat it does
Tab / Shift+TabMoves between the buttons, staying inside the dialog.
Enter / SpacePresses the focused button.
EscCancels and closes.

Props

PropTypeDefaultDescription
openboolean—Shows the dialog.
titleReactNode—The question, naming the thing affected.
childrenReactNode—What is lost, in a sentence or two.
confirmLabelstring—Verb and object: Delete key. Required.
cancelLabelstring'Cancel'The safe action.
tone'destructive' | 'primary''destructive'Primary when nothing is lost, such as a pause.
consequenceReactNode—Warning panel for knock-on effects.
loadingbooleanfalseSpinner on the confirm while the action runs.
onConfirm() => void—Runs the action.
onCancel() => void—Cancel, Esc, the close button or the scrim.
closeOnOverlaybooleantrueWhether a scrim click cancels.
containedbooleanfalseFills the nearest positioned parent instead of the viewport.
autoFocusbooleantrueMoves focus to Cancel on open.

Tokens

TokenValueWhere it lands
max-w-sm384pxPanel width.
--radius-3xl16pxPanel corners.
--dialog-overlayrgba(10, 9, 11, 0.5)The scrim, with a 2px blur.
--color-error#E12121Destructive confirm fill.