Skip to content

ConfirmDialog

A Dialog that asks the reader to confirm one action, with a slot for a one-time code when the action needs a step-up.

import { ConfirmDialog } from '@zitdevs/ui';

Both demos are hydrated islands, since the focus rules and the pending state need the browser. Open the first: focus starts on Cancel, and confirming holds the dialog for a moment, with Escape and the backdrop doing nothing. Open the second: the code field has focus. Submit any code but 123456 and the error is announced with focus still in the field.

Remove Ada Lovelace?

She loses access to the organization at once.

Confirm it is you

Enter the six-digit code from your authenticator app to approve.

Try 123456.

<ConfirmDialog
id="step-up"
title="Confirm it is you"
description="Enter the six-digit code from your authenticator app."
confirmLabel="Verify and approve"
initialFocus="slot"
pending={pending}
error={error}
action={verify}
>
<Field
id="code"
name="code"
label="Verification code"
autoComplete="one-time-code"
inputMode="numeric"
/>
</ConfirmDialog>

It takes every Dialog prop except footer, children, closedby, dismissible and labels, which it sets itself. Its trigger is a dialogTriggerProps(id) button.

Prop Type Default Notes
id string required The dialog’s id; its form is <id>-form.
title string required The question: “Remove Ada Lovelace?”.
confirmLabel string required Names the action: “Remove member”, not “OK”.
cancelLabel string Cancel Over labels.cancel.
tone 'default' | 'destructive' 'default' destructive confirms in the danger colour.
action string | (formData) => void — A function runs in the browser; an address posts natively (method="post").
pending boolean false A request is on its way: confirm is busy, Cancel is disabled, nothing can dismiss or resend it.
error string — Why it failed, in a role="alert"; the slot’s field takes focus back.
initialFocus 'cancel' | 'slot' 'cancel' slot for a one-time code, which commits nothing.
children ReactNode — The slot, inside the dialog’s form: a code Field.
labels Partial<ConfirmDialogLabels & DialogLabels> English { cancel, working, close }. es.confirmDialog and es.dialog from labels/es.

Exported types: ConfirmDialogProps, ConfirmDialogLabels, and the label sets confirmDialogLabels.

  • The native modal: the page behind it is inert, focus is trapped inside, and on close it goes back to the button that opened it.
  • Initial focus goes to Cancel, the safest action. With initialFocus="slot" it goes to the code field instead, because typing a code commits nothing.
  • Pending sets closedby="none": Escape and the backdrop are inert, the corner button is gone and Cancel is disabled. The confirm button is replaced by a busy one with aria-busy, and the form drops its action, so Enter in the field cannot send a second request.
  • Error renders in a role="alert", so it is announced, and the code field takes focus back so the reader types again where they were.
  • Give the code field autoComplete="one-time-code" and inputMode="numeric".

The dialog is server HTML. A string action posts natively, and the confirm button is a submit button of the form with or without a script. What needs the browser: opening it in a browser without the HTML invoker commands, the initial focus, a function action, and the pending and error rules above. The small client part of the form runs once React hydrates it. A flow that must work without JavaScript should be a page instead.

surface-raised, ink, muted and body from the dialog; primary for the confirm button, or danger-strong when destructive (4.5:1 with white text); the alert’s danger roles; the focus ring.