# Alert Dialog

> Alert Dialog: anatomy, keyboard behavior, state, and theming in Askr.

Source: [https://askrjs.com/docs/components/alert-dialog](https://askrjs.com/docs/components/alert-dialog)

Status: stable. Packages: @askrjs/ui/alert-dialog, @askrjs/themes/alert-dialog.

**Published packages are authoritative.** Examples may lag behind a published contract. When guidance differs, verify the exports and TypeScript declarations in your installed package, then file an issue.

## Example

```tsx
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger, Button } from '@askrjs/themes/components';

<AlertDialog>
  <AlertDialogTrigger asChild><Button variant="destructive">Delete project</Button></AlertDialogTrigger>
  <AlertDialogContent>
    <AlertDialogTitle>Delete project?</AlertDialogTitle>
    <AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
    <AlertDialogCancel>Cancel</AlertDialogCancel>
    <AlertDialogAction>Delete</AlertDialogAction>
  </AlertDialogContent>
</AlertDialog>
```

## Published props

Generated from the TypeScript declarations shipped by the installed package.

### `AlertDialogActionAsChildProps`

Import from `@askrjs/ui/alert-dialog`.

- `asChild: true;`
- `children: JSXElement;`
- `disabled?: boolean | undefined;`
- `onPress?: ((event: PressEvent) => void) | undefined;`
- `ref?: Ref<Element>;`
- `type?: undefined;`

### `AlertDialogActionProps`

Import from `@askrjs/ui/alert-dialog`.

- `asChild?: false | undefined;`
- `children?: unknown;`
- `disabled?: boolean | undefined;`
- `onPress?: ((event: PressEvent) => void) | undefined;`
- `ref?: Ref<HTMLButtonElement>;`
- `type?: "button" | "submit" | "reset" | undefined;`

### `AlertDialogCancelAsChildProps`

Import from `@askrjs/ui/alert-dialog`.

- `asChild: true;`
- `children: JSXElement;`
- `disabled?: boolean | undefined;`
- `onPress?: ((event: PressEvent) => void) | undefined;`
- `ref?: Ref<Element>;`
- `type?: undefined;`

### `AlertDialogCancelProps`

Import from `@askrjs/ui/alert-dialog`.

- `asChild?: false | undefined;`
- `children?: unknown;`
- `disabled?: boolean | undefined;`
- `onPress?: ((event: PressEvent) => void) | undefined;`
- `ref?: Ref<HTMLButtonElement>;`
- `type?: "button" | "submit" | "reset" | undefined;`

### `AlertDialogContentAsChildProps`

Import from `@askrjs/ui/alert-dialog`.

- `asChild: true;`
- `children: JSXElement;`
- `forceMount?: boolean | undefined;`
- `onDismiss?: (() => void) | undefined;`
- `onEscapeKeyDown?: ((event: KeyboardEvent) => void) | undefined;`
- `onInteractOutside?: ((event: Event) => void) | undefined;`
- `onPointerDownOutside?: ((event: PointerEvent) => void) | undefined;`
- `ref?: Ref<Element>;`
- `role?: "alertdialog" | "dialog" | undefined;`

### `AlertDialogContentOwnProps`

Import from `@askrjs/ui/alert-dialog`.

- `forceMount?: boolean | undefined;`
- `onDismiss?: (() => void) | undefined;`
- `onEscapeKeyDown?: ((event: KeyboardEvent) => void) | undefined;`
- `onInteractOutside?: ((event: Event) => void) | undefined;`
- `onPointerDownOutside?: ((event: PointerEvent) => void) | undefined;`
- `role?: "alertdialog" | "dialog" | undefined;`

### `AlertDialogContentProps`

Import from `@askrjs/ui/alert-dialog`.

- `asChild?: false | undefined;`
- `children?: unknown;`
- `forceMount?: boolean | undefined;`
- `onDismiss?: (() => void) | undefined;`
- `onEscapeKeyDown?: ((event: KeyboardEvent) => void) | undefined;`
- `onInteractOutside?: ((event: Event) => void) | undefined;`
- `onPointerDownOutside?: ((event: PointerEvent) => void) | undefined;`
- `ref?: Ref<HTMLDivElement>;`
- `role?: "alertdialog" | "dialog" | undefined;`

### `AlertDialogDescriptionAsChildProps`

Import from `@askrjs/ui/alert-dialog`.

- `asChild: true;`
- `children: JSXElement;`
- `ref?: Ref<Element>;`

### `AlertDialogDescriptionProps`

Import from `@askrjs/ui/alert-dialog`.

- `asChild?: false | undefined;`
- `children?: unknown;`
- `ref?: Ref<HTMLParagraphElement>;`

### `AlertDialogOverlayAsChildProps`

Import from `@askrjs/ui/alert-dialog`.

- `asChild: true;`
- `children: JSXElement;`
- `forceMount?: boolean | undefined;`
- `ref?: Ref<Element>;`

### `AlertDialogOverlayOwnProps`

Import from `@askrjs/ui/alert-dialog`.

- `forceMount?: boolean | undefined;`

### `AlertDialogOverlayProps`

Import from `@askrjs/ui/alert-dialog`.

- `asChild?: false | undefined;`
- `children?: unknown;`
- `forceMount?: boolean | undefined;`
- `ref?: Ref<HTMLDivElement>;`

### `AlertDialogOwnProps`

Import from `@askrjs/ui/alert-dialog`.

- `children?: unknown;`
- `defaultOpen?: boolean | undefined;`
- `id?: string | undefined;`
- `modal?: boolean | undefined;`
- `onOpenChange?: ((open: boolean) => void) | undefined;`
- `open?: boolean | undefined;`

### `AlertDialogPortalProps`

Import from `@askrjs/ui/alert-dialog`.

- `children?: unknown;`

### `AlertDialogProps`

Import from `@askrjs/ui/alert-dialog`.

- `children?: unknown;`
- `defaultOpen?: boolean | undefined;`
- `id?: string | undefined;`
- `modal?: boolean | undefined;`
- `onOpenChange?: ((open: boolean) => void) | undefined;`
- `open?: boolean | undefined;`

### `AlertDialogTitleAsChildProps`

Import from `@askrjs/ui/alert-dialog`.

- `asChild: true;`
- `children: JSXElement;`
- `ref?: Ref<Element>;`

### `AlertDialogTitleProps`

Import from `@askrjs/ui/alert-dialog`.

- `asChild?: false | undefined;`
- `children?: unknown;`
- `ref?: Ref<HTMLHeadingElement>;`

### `AlertDialogTriggerAsChildProps`

Import from `@askrjs/ui/alert-dialog`.

- `asChild: true;`
- `children: JSXElement;`
- `disabled?: boolean | undefined;`
- `onPress?: ((event: PressEvent) => void) | undefined;`
- `ref?: Ref<Element>;`
- `type?: undefined;`

### `AlertDialogTriggerProps`

Import from `@askrjs/ui/alert-dialog`.

- `asChild?: false | undefined;`
- `children?: unknown;`
- `disabled?: boolean | undefined;`
- `onPress?: ((event: PressEvent) => void) | undefined;`
- `ref?: Ref<HTMLButtonElement>;`
- `type?: "button" | "submit" | "reset" | undefined;`

## Purpose

Alert Dialog is Dialog configured for one job: forcing a decision. It's for destructive or hard-to-reverse actions — deleting a record, discarding unsaved changes — where you want to interrupt the user and make them explicitly confirm or back out rather than dismissing it accidentally with a stray click or Escape.

## Install and import

Import behavior from `@askrjs/ui/alert-dialog` and styling from `@askrjs/themes/alert-dialog`, both real subpaths. `AlertDialogAction` and `AlertDialogCancel` really are `DialogClose` under alias names with no logic of their own, and `AlertDialogOverlay`/`AlertDialogTitle`/`AlertDialogDescription` pass straight through to Dialog's parts — but `AlertDialogTrigger` and `AlertDialogContent` aren't bare re-exports; both wrap the underlying Dialog part with alert-dialog-specific dismissal guarding, so don't assume every piece in this tree is a zero-logic alias just because most of them are.

## Live examples

Structure mirrors Dialog: `AlertDialog` wraps an `AlertDialogTrigger` and a portal containing `AlertDialogContent`, `AlertDialogTitle`, and `AlertDialogDescription`. The part that's actually distinct is the footer — pair `AlertDialogCancel` with `AlertDialogAction` so there's always an explicit way to back out alongside the destructive action.

## Anatomy

`AlertDialogContent` is a dedicated component, but it does not set `role="alertdialog"` for you — it renders through `DialogContent` with the same default role Dialog uses, so pass `role="alertdialog"` explicitly if you want that stronger semantic than plain `role="dialog"`. What `AlertDialogContent` and `AlertDialogTrigger` actually add over a straight Dialog re-export is behavioral, not role-related: the trigger guards against re-activation dismissing an already-open dialog, and the content wraps `onEscapeKeyDown`/`onPointerDownOutside` so outside pointer dismissal is blocked while Escape still works — reflecting the "confirm or explicitly cancel" pattern this component is for.

## State model

State is the same open/closed boolean as Dialog, since `AlertDialogProps` is literally `DialogProps` under a type alias — `open`, `defaultOpen`, and `onOpenChange` behave identically. The meaningful difference isn't in the state shape, it's in what the two footer actions are expected to do: `AlertDialogCancel` should always close without side effects, `AlertDialogAction` should perform the action and then close.

## Keyboard and accessibility

The a11y contract calls for both a primary action and a cancel action to be present — `ALERT_DIALOG_A11Y_CONTRACT.ACTION_REQUIREMENTS` flags both as required, so don't ship an alert dialog with only a single button. `aria-labelledby`/`aria-describedby` from `DialogTitle`/`DialogDescription` are wired up the same way Dialog does it, but `role="alertdialog"` is not applied automatically — the component defaults to Dialog's own role, so set `role="alertdialog"` on `AlertDialogContent` explicitly if you want assistive tech to treat it as an interruption needing an explicit response rather than a plain dialog.

## Styling and tokens

Because the overlay, content surface, and animations are shared with Dialog, alert dialogs pick up the same `--ak-color-backdrop`, `--ak-color-surface-raised`, `--ak-color-border`, and z-index tokens out of the box. The theme layer's own `alert-dialog.css` is intentionally small — it only strengthens the content's border (`border-width: 1px` against `--ak-color-border`) on top of Dialog's shared styling; it doesn't add its own action-row layout or automatically apply a destructive variant to `AlertDialogAction` — pick that button variant yourself the same way you would on any other `Button`.

## API

`AlertDialogAction` and `AlertDialogCancel` are both just `DialogClose` — button-like components with `onPress`/`disabled`, no special props of their own beyond what Dialog's close button already supports. `AlertDialogContent` supports the same `forceMount`, `onEscapeKeyDown`, `onPointerDownOutside`, `onInteractOutside`, and `onDismiss` props as `DialogContent`; there's no alert-dialog-specific prop surface beyond the role.

## Edge cases

Because `AlertDialogCancel` and `AlertDialogAction` are both plain close buttons under the hood, nothing stops you from wiring `onPress` on `AlertDialogCancel` to do something other than a no-op cancel — resist that, since it breaks the pattern users expect from this component. If the destructive action can fail, keep the dialog open and surface the error inside `AlertDialogContent` rather than letting `AlertDialogAction` close it optimistically.

## Related pages

See Dialog for the full prop reference and the shared portal/overlay/content anatomy that Alert Dialog builds on. If the interruption doesn't need a confirm/cancel pair — just information the user can dismiss with a click anywhere — a plain Dialog or a Popover is a better fit.

## Documentation navigation

[Previous](https://askrjs.com/docs/components/dialog/index.md) | [Next](https://askrjs.com/docs/components/popover/index.md)
