AlertDialog
Confirmation modal that forces a user response — no escape, no click-outside.
At a glance
- Compose:
AlertDialog,AlertDialogTrigger,AlertDialogContent,AlertDialogTitle,AlertDialogDescription,AlertDialogCancel,AlertDialogAction,AlertDialogFooter. Triggers / Cancel / Action useasChildby default — wrap any element and it becomes the activator. - Forces a response: backdrop click does not close, Escape does not close. The user MUST press Cancel or Action.
- Initial focus lands on Cancel — the least destructive default — so a stray Enter keypress can't fire the destructive action.
- Accessibility:
role="alertdialog"witharia-modal,aria-labelledbyon the title,aria-describedbyon the description. - Cross-platform: uses RN
<Modal>as the visibility primitive. Web layers on focus trap, scroll lock, focus restore. Subtle scale-in animation (150ms) honorsprefers-reduced-motion.
When to use AlertDialog vs Dialog
Use AlertDialog for destructive or otherwise irreversible confirmations — "Delete project?", "Sign out
everyone?", "Discard unsaved changes?". The user has to make an explicit choice, which matches the weight of the
action.
Use Dialog for everything else — forms, info, settings, embedded flows. Dialog allows Escape and click-outside
to dismiss, which is the expected affordance for forgettable, low-stakes interactions.
Choosing the wrong one is a real accessibility / UX bug: if Dialog gates a destructive action, users will lose work by tapping outside; if AlertDialog gates a form, users will feel trapped.
Preview
Open state — open, defaultOpen, onOpenChange
open (controlled) + onOpenChange is the parent-driven shape; pass
defaultOpen for uncontrolled mode. Mixing the two prefers controlled
and ignores defaultOpen. Trigger / Cancel / Action subcomponents
already flip the state for you, so most call sites don't need either.
Anatomy
| Subcomponent | Role |
|---|---|
AlertDialog | Root — owns open state (controlled or uncontrolled). |
AlertDialogTrigger | Element that opens the dialog. asChild by default. |
AlertDialogContent | The visible surface. Renders only while open. Backdrop click and Escape do nothing. |
AlertDialogTitle | Heading. Wires aria-labelledby. |
AlertDialogDescription | Body description. Wires aria-describedby. |
AlertDialogCancel | Dismiss action. Receives initial focus. Forwards onPress, then closes. |
AlertDialogAction | Confirming / destructive action. Forwards onPress, then closes. |
AlertDialogFooter | Right-aligned row for the Cancel / Action buttons. |
Usage
Props
AlertDialog
| Prop | Type | Default | Description |
|---|---|---|---|
defaultOpen | boolean | false | Uncontrolled initial open state. @defaultValue false |
onOpenChange | (open: boolean) => void | — | Fires with the new open state. |
open | boolean | — | Controlled open state. |
AlertDialogTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | true | Render the child as the trigger (Slot pattern). Default true. |
className | string | — | — |
testID | string | — | — |
AlertDialogContent
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | — |
testID | string | — | — |
AlertDialogCancel
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | true | Render the child as the cancel button (Slot pattern). Default true. |
className | string | — | — |
onPress | (event?: unknown) => void | — | Forwarded to the wrapped child / fallback Pressable. Fires before close. |
testID | string | — | — |
AlertDialogAction
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | true | Render the child as the action (Slot pattern). Default true. |
className | string | — | — |
onPress | (event?: unknown) => void | — | Forwarded to the wrapped child / fallback Pressable. Fires before close. |
testID | string | — | — |