abaabil

Alert dialog

A dialog that interrupts and demands a decision. A native <dialog> carrying role="alertdialog", which changes how it is announced and what it is allowed to do.

Example (a11y tier)

Delete this project?

Everything in it is removed permanently. This cannot be undone.

Two things there are worth trying with the keyboard. Clicking the backdrop does nothing. And when it opens, focus is on Cancel.

Import

import AlertDialog from 'abaabil/alert-dialog'         // structure only
import AlertDialog from 'abaabil/alert-dialog/styled'  // + CSS
import AlertDialog from 'abaabil/alert-dialog/a11y'    // + label, description, safe focus

Why it is not a variant of dialog

Three things separate it from dialog, and folding them into a variant prop would make it possible to get a destructive confirmation that dismisses when you click beside it, which is the exact bug this component rules out.

  • It requires a description. role="alertdialog" causes the description to be announced the moment it opens. A dialog with that role and nothing to describe announces its title twice and stops, which is worse than a plain dialog. The component warns in development if you omit it.
  • It does not light-dismiss. Escape still works, because removing that would trap a keyboard user with no way out. Clicking the backdrop does not, because the answer matters.
  • It focuses the least destructive action.

data-safe-action

The browser focuses the first focusable element in a dialog, which in a confirmation is usually whichever button the author wrote first. A confirmation that opens with Delete focused is one Enter keypress away from deleting.

So this tier moves focus to whatever carries data-safe-action when the dialog opens, and falls back to the platform's behaviour when nothing does. It is an attribute rather than a prop because the safe control is often nested inside your own layout, not a direct child.

<Button data-safe-action onClick={cancel}>Cancel</Button>
<Button onClick={destroy}>Delete</Button>

Coverage

Only two of the nine libraries on the comparison ship one: Radix and shadcn/ui, which is Radix. Chakra folded it into its dialog behind a role prop and Ant Design's Popconfirm is a popover rather than a modal, so neither is counted; both ship the capability without shipping the component.

Props

PropTypeDefaultTierDescription
openbooleanfalsea11yDrives showModal() and close().
labelstringa11yThe question, rendered as a heading.
descriptionstringa11yWhat happens if they say yes. Announced on open.
onClose() => voida11yEscape and close(). Not the backdrop.
classNamestringallMerged with the base class.