Skip to content
garn

Alert Dialog

A modal that interrupts to force an explicit confirm/cancel decision.

Stablev0.4.2added in v0.1.0@garn/ui/alert-dialog
On this page

Installation

garn is copy-in — the garn CLI writes this component's source into your project, so you own and can edit it. It resolves any base files and installs the npm dependencies below for you.

terminal
npx garn-ui add alert-dialog
First time? Set up garn in your project
Registry
alert-dialog
Deps
@radix-ui/react-alert-dialog
Registry deps
buttonutilsframe

Import

import { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogTitle, AlertDialogDescription, AlertDialogHeader, AlertDialogFooter, AlertDialogAction, AlertDialogCancel } from "@garn/ui/alert-dialog";

Anatomy

The parts this component is built from — compose them to assemble it.

AlertDialogRequired

Root — owns the open state. No DOM of its own.

AlertDialogTrigger[data-slot="alert-dialog-trigger"]

Opens the dialog (asChild to wrap your own button).

AlertDialogContentRequired[data-slot="alert-dialog-content"]

Focus-trapped surface (portals its own overlay). No dismiss-X — closing is explicit.

AlertDialogTitleRequired[data-slot="alert-dialog-title"]

Accessible name for the dialog (required; sr-only if visually hidden).

AlertDialogDescription[data-slot="alert-dialog-description"]

The consequence text, wired to aria-describedby.

AlertDialogHeader[data-slot="alert-dialog-header"]

Layout wrapper for title + description.

AlertDialogFooter[data-slot="alert-dialog-footer"]

Layout wrapper for the actions (right-aligned on ≥sm).

AlertDialogActionRequired[data-slot="alert-dialog-action"]

The confirm button (styled primary via buttonVariants).

AlertDialogCancelRequired[data-slot="alert-dialog-cancel"]

The cancel button (styled outline); initial focus lands here.

Props

The component's public props and their types.

No component-specific props — this is a thin wrapper over its native element.

Styling

Target these data-slots and states, and remap these tokens, to restyle without forking the component.

[data-slot="alert-dialog-content"]

States

SelectorState
[data-state=open]open
[data-state=closed]closed
PropertyTokenTier
padding--garn-pad-surfacesemantic · air
gap--garn-gap-stacksemantic · air
headerGap--garn-gap-fieldsemantic · air
motion--garn-motion-fastsemantic

When to use

Force an explicit decision before continuing — confirming a destructive or irreversible action (delete, discard, sign out).

Reach for something else when

  • A non-blocking message or a routine form (use dialog)
  • a transient status (use a toast)
  • contextual info near a control (use popover).

Overview

AlertDialog forces an explicit decision before continuing — confirming a destructive or irreversible action like delete, discard, or sign out. Unlike Dialog, AlertDialogContent has no dismiss-X and ignores outside-click: the only way out is the AlertDialogAction (confirm) or AlertDialogCancel (which takes initial focus). Use it sparingly, only when proceeding has real consequences; for a routine form or message, a Dialog is right, and for a non-blocking confirmation a Sonner toast with Undo is often kinder.

Guidelines

Reserve it for consequential, irreversible actions. If the action is easily undone, prefer an optimistic update with an Undo toast over interrupting the user. Overusing alert dialogs for harmless steps trains people to confirm on reflex.

Name the consequence, not the mechanism. The Title + Description should state what will happen ("Delete 3 files? This can't be undone"), and the action button should name the act ("Delete", not "OK"). Match the button's tone to the risk — destructive confirms read as danger.

Make Cancel the safe default. Initial focus lands on Cancel and Escape cancels, so an accidental Enter never destroys anything. Keep the choice binary and the copy short — this is a decision point, not a place for extra fields.

Best practices

Do
  • Always include an AlertDialogTitle and an AlertDialogDescription that states the consequence.
  • Use AlertDialogAction for the confirm and AlertDialogCancel for the safe out; let Cancel keep initial focus.
  • Style a destructive confirm's Action with the destructive intent.
Don't
  • Don't use an alert-dialog for ordinary, non-destructive tasks — that's a dialog.
  • Don't make Escape or overlay-click silently confirm — closing must be Cancel-safe.
  • Don't omit the description; 'Are you sure?' alone doesn't state the stakes.

Content guidelines

  • Title the decision, not the question — “Delete 3 files?” rather than “Are you sure?”.
  • Use the description to state the consequence and whether it can be undone.
  • Label the confirm button with the action (“Delete”), never “Yes” / “OK”.

Troubleshooting

Screen readers can't name the dialog / a console warning about a missing title.

Cause. AlertDialogContent without an AlertDialogTitle (Radix requires it).

Fix. Add an AlertDialogTitle (sr-only if you don't want it visible) and an AlertDialogDescription.

Users dismiss the prompt by clicking outside and nothing is confirmed — as intended, but surprising if you expected dialog behavior.

Cause. alert-dialog deliberately does not close on overlay click; only Action/Cancel/Escape resolve it.

Fix. If you want overlay-click dismissal, you want a dialog, not an alert-dialog.

Accessibility

Role
alertdialog
ARIA APG
alertdialog
Focus
Focus trapped inside the content, initially on Cancel; returns to the trigger on close.

Accessibility requirements

warn

Every AlertDialogContent must contain an AlertDialogTitle (wrap it in sr-only to hide it visually).

when AlertDialogContent has no AlertDialogTitle

Keyboard

EscapeCancel and close (treated as the Cancel action).
TabShift+TabCycle focus within the dialog (focus is trapped).
EnterActivate the focused action button.
A1.3.1Info and RelationshipsA2.1.1KeyboardA2.4.3Focus OrderA4.1.2Name, Role, Value
  • role=alertdialog + aria-modal; labelled by AlertDialogTitle and described by AlertDialogDescription.
  • Initial focus lands on Cancel; focus returns to the trigger on close.
  • Unlike dialog, clicking the overlay does NOT dismiss it — the choice is explicit.