---
title: Alert Dialog
description: A modal that asks for a decision before continuing with an important action.
---

<PackageInfo name="alert-dialog" />

**bun**

```bash
bun add @data-slot/alert-dialog
```

**npm**

```bash
npm install @data-slot/alert-dialog
```

**pnpm**

```bash
pnpm add @data-slot/alert-dialog
```

## Anatomy

The overlay is required. The portal is optional and gets moved to `document.body` while the dialog is open. `alert-dialog-action` does not close the dialog on its own — wire it to your own handler.

```html
<div data-slot="alert-dialog">
  <button data-slot="alert-dialog-trigger">Delete project</button>

  <div data-slot="alert-dialog-portal">
    <div data-slot="alert-dialog-overlay" hidden></div>
    <div data-slot="alert-dialog-content" hidden>
      <div data-slot="alert-dialog-header">
        <div data-slot="alert-dialog-media">!</div>
        <h2 data-slot="alert-dialog-title">Delete project?</h2>
        <p data-slot="alert-dialog-description">
          This action cannot be undone.
        </p>
      </div>

      <div data-slot="alert-dialog-footer">
        <button data-slot="alert-dialog-cancel">Cancel</button>
        <button data-slot="alert-dialog-action">Delete</button>
      </div>
    </div>
  </div>
</div>
```

## Examples

### Confirm an action

<Example name="alert-dialog" />

### Require an explicit choice

Escape will not dismiss this one — `data-close-on-escape="false"` forces a choice between Cancel and Continue.

<Example name="alert-dialog" variant="extra" />

## API reference

### Initialization

#### `create(scope?)`

Auto-discovers and binds all alert dialogs in a scope.

```ts
import { create } from "@data-slot/alert-dialog";

const controllers = create();
```

#### `createAlertDialog(root, options?)`

```ts
import { createAlertDialog } from "@data-slot/alert-dialog";

const alertDialog = createAlertDialog(element, {
  closeOnClickOutside: false,
  onOpenChange: (open) => console.log(open),
});
```

### Slots

#### Runtime Slots

- `alert-dialog` - Root element
- `alert-dialog-trigger` - Element that toggles the alert dialog
- `alert-dialog-portal` - Optional element portaled to `document.body`
- `alert-dialog-overlay` - Required overlay
- `alert-dialog-content` - Required modal content
- `alert-dialog-title` - Title used for `aria-labelledby`
- `alert-dialog-description` - Description used for `aria-describedby`
- `alert-dialog-cancel` - Close button

#### Style-only Slots

- `alert-dialog-header` - Optional layout wrapper for the title, description, and media.
- `alert-dialog-footer` - Optional layout wrapper for the action and cancel buttons.
- `alert-dialog-media` - Optional icon or illustration area in the header.
- `alert-dialog-action` - Confirmation action button; wire your own handler and close the dialog explicitly.

`alert-dialog-action` is intentionally just a styled action slot. It does not close automatically.

### Data Attributes

Set these on the `alert-dialog` root. JavaScript options take precedence. Empty attributes or `"true"` enable a boolean; `"false"` disables it.

| Attribute | Type | Default | Description |
| --- | --- | --- | --- |
| `data-default-open` | `boolean` | `false` | Initial open state |
| `data-close-on-click-outside` | `boolean` | `false` | Close when clicking the overlay |
| `data-close-on-escape` | `boolean` | `true` | Close on Escape |
| `data-lock-scroll` | `boolean` | `true` | Lock page scroll while open |

#### State Attributes

- `data-state="open" | "closed"` on root, portal, overlay, and content
- `data-open` / `data-closed` on root, portal, overlay, and content
- `data-stack-index` on overlay and content when multiple modal layers are open

### Options

| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `defaultOpen` | `boolean` | `false` | Initial open state |
| `onOpenChange` | `(open: boolean) => void` | `undefined` | Called when open state changes |
| `closeOnClickOutside` | `boolean` | `false` | Close when clicking the overlay |
| `closeOnEscape` | `boolean` | `true` | Close when pressing `Escape` |
| `lockScroll` | `boolean` | `true` | Lock page scroll while open |

### Controller

| Method | Description |
| --- | --- |
| `open()` | Open the alert dialog |
| `close()` | Close the alert dialog |
| `toggle()` | Toggle the alert dialog |
| `destroy()` | Remove listeners and cleanup |
| `isOpen` | Current open state |

#### Controller Destruction

`destroy()` permanently disposes the controller and hides any open surface without
emitting an additional change event. Repeated destruction is safe; methods on the
old controller become no-ops. Create a new controller on the same root to rebind it.

Destruction restores prior focus, falling back to a surviving trigger if the prior
target was removed. Destroying an unopened modal does not move focus.

### Events

| Event | Detail | Description |
| --- | --- | --- |
| `alert-dialog:change` | `{ open: boolean }` | Fired when open state changes |
| `alert-dialog:set` | `{ open: boolean }` | Programmatically set open state |

### Accessibility

- `role="alertdialog"` on content
- `aria-modal="true"` on content
- `aria-labelledby` / `aria-describedby` wiring from title and description
- Focus is trapped while open
- Focus returns to the trigger or previously focused element when closed
