ConfirmDialog

Asks people to confirm an action whose consequence needs a sentence.

BetaSince 1.0.0
On this page

Import

import { ConfirmDialog } from '@envsemble/envui';

Usage

A ConfirmDialog opens from its trigger, such as a Button. Its title asks the question, such as “Delete Northwind launch?”, its description says what confirming does and whether it can be undone, and confirmLabel names the consequence, such as Delete project.

  • cancelLabel names the cancel button.
  • children holds more content between the heading and the actions, such as the one field a confirmation holds, where Enter confirms.
  • confirmDisabled disables the confirm button, and Enter in a field doesn't confirm, such as until a typed name matches.
  • A press outside doesn't close it.
DeleteProject.tsx
import { useState } from 'react';
import { Button, ConfirmDialog, Column, Text } from '@envsemble/envui';

export default function DeleteProject() {
  const [result, setResult] = useState('');
  return (
    <Column gap={4} align="start">
      <ConfirmDialog
        trigger={<Button variant="secondary">Delete project</Button>}
        tone="danger"
        title="Delete Northwind launch?"
        description="This deletes the project and its files for everyone. It can’t be undone."
        confirmLabel="Delete project"
        onConfirm={() => setResult('Northwind launch deleted')}
      />
      <Text role="status">{result}</Text>
    </Column>
  );
}

Tone

tone is neutral, the default, where focus starts on the confirm button, or danger, for an action that deletes or ends something: the confirm button is a danger one and focus starts on Cancel, so a hurried Enter doesn't confirm.

<ConfirmDialog
  tone="danger"
  trigger={<Button tone="danger">Delete project</Button>}
  title="Delete Northwind launch?"
  description="This deletes the project and its files for everyone. It can’t be undone."
  confirmLabel="Delete project"
  onConfirm={deleteProject}
/>

An action that can fail

onConfirm runs the action, once per opening: further presses, such as a double-click's second, are ignored until it fails.

  • The dialog closes when it returns; when it returns a promise, the confirm button is pending, with aria-busy, nothing dismisses the dialog, and it closes once the promise resolves.
  • A rejected promise or a thrown error keeps it open and goes to reportError; show what went wrong with error, a danger Alert above the actions that is announced.
  • The dialog is a form, so hold no form of your own in it; use Dialog for one.
<ConfirmDialog
  trigger={<Button variant="secondary">Archive project</Button>}
  title="Archive Northwind launch?"
  confirmLabel="Archive project"
  error={error || undefined}
  onConfirm={() => {
    setError('');
    return archive(); // A promise; a rejected one keeps the dialog open.
  }}
/>

From a menu

Without a trigger, open it with open and onOpenChange, which receives the requested state and why: from the trigger, Esc, Cancel or after onConfirm finishes. defaultOpen opens an uncontrolled one on the first render. finalFocus sets where focus goes on closing, such as the menu's button, since the menu item is gone; by default it returns to the trigger.

<Menu.Item onClick={() => setOpen(true)}>Delete project…</Menu.Item>

<ConfirmDialog
  open={open}
  onOpenChange={setOpen}
  finalFocus={menuButton}
  tone="danger"
  title="Delete Northwind launch?"
  confirmLabel="Delete project"
  onConfirm={deleteProject}
/>

Customize

A ConfirmDialog is an alert dialog with Dialog's parts: the surface, env-dialog, the question, env-dialog-title, the description, env-dialog-description, and the actions, env-dialog-actions, with Cancel first and the confirm button last. The error is an Alert, env-alert, above the actions. Its surface looks as Dialog's does.

Accessibility

You provide

  • A title that asks the question, and a confirmLabel that names the consequence.
  • finalFocus where the trigger is gone or something other than trigger opened the dialog.

envUI provides

  • role="alertdialog", named by title and described by description.
  • Focus trapped inside, and returned on close.
  • aria-busy while the action runs, and the error announced as an alert.

Props

ConfirmDialog

Asks people to confirm an action whose consequence needs a sentence, such as deleting a project: an alert dialog with a question, a description, Cancel and a confirm button that names the consequence. It waits for onConfirm's promise, pending, and stays open when it fails. className, style, ref and data attributes go to the dialog's surface.

PropTypeDescription
open
boolean
Whether the dialog is open, for a dialog the application controls with onOpenChange.
defaultOpenDefault false
boolean
Whether a dialog the application doesn't control is open on the first render.
onOpenChange
(open: boolean, details: DialogOpenChangeDetails) => void
Called with the requested state, and why, when the dialog opens or closes: from the trigger, Escape, Cancel, or after onConfirm finishes. Not called for a dismissal that a running onConfirm blocks.
trigger
ReactElement
The element that opens the dialog, such as a Button. Omit it for a dialog the application opens with open, such as from a menu item.
titlerequired
ReactNode
The question, which names the dialog, such as “Delete Northwind launch?”.
description
ReactNode
What confirming does and whether it can be undone; it describes the dialog.
children
ReactNode
More content between the heading and the actions, such as what else the action affects, or the one field a confirmation holds, such as a typed name. The dialog is a form: Enter in a field confirms as the confirm button does, through onConfirm. Hold no form here; use Dialog for one.
confirmLabelrequired
string
The confirm button's label: a verb that names the consequence, such as Delete project.
cancelLabelDefault 'Cancel', or EnvUIProvider's messages.confirmDialog.cancel
string
The cancel button's label.
toneDefault 'neutral'
'neutral''danger'
danger for an action that deletes or ends something: the confirm button is a danger one and focus starts on Cancel, so a hurried Enter doesn't confirm. neutral starts focus on the confirm button.
onConfirmrequired
() => void | Promise<void>
Runs the action when the confirm button is pressed, or Enter is pressed in a field in the dialog. The dialog closes when it returns, or, when it returns a promise, once the promise resolves; while it runs, the confirm button is pending and nothing dismisses the dialog. It runs once per opening: further presses, such as the second click of a double-click, are ignored until it fails or the dialog opens again. A rejected promise or a thrown error keeps it open and is passed to reportError, so show what went wrong with error.
confirmDisabledDefault false
boolean
Whether the confirm button is disabled, and Enter in a field doesn't confirm, such as for a confirmation that waits on a typed name.
error
ReactNode
What went wrong, shown as a danger Alert above the actions and announced.
finalFocus
DialogFocusTarget
The element to focus when the dialog closes, such as the menu button whose item opened it: its ref, or a function of how the dialog was opened that returns it, as on Dialog. By default focus returns to the trigger, or to the element that had focus when it opened.

Also accepts the native props of <div>, such as ref, className and aria-* attributes.

Part names

Each part's class and state attributes are public and versioned, for an application's CSS to style.

env-confirm-dialog-form
The form that holds the dialog's fields and its confirming action.

Strings

EnvUIProvider's messages overrides each, and a component's own label prop wins over it.

messages.confirmDialog.cancel
"Cancel" The button that closes the dialog without confirming.

Changelog

1.0.0

ConfirmDialog, an alert dialog with a neutral or danger tone that waits for its action and stays open when it fails.

1.0.0-prerelease.6

The dialog fades in with --env-motion-ease-enter, so it shows from its first frames rather than late, while it rises into place as before.

confirmDisabled disables the confirm button, such as for a confirmation that waits on a typed name.

1.0.0-prerelease.5

The dialog takes the popups' color and soft shadow, with no outline edge, as Dialog does.