---
title: Alert Dialog
description: A modal dialog that interrupts the user with important content and expects a response.
icon: circle-alert
sidebar:
  badge: Updated
author:
  name: shadcn
  url: https://github.com/shadcn
search:
  keywords: [confirm, confirmation, modal]
related:
  - /dialog
  - /alert
mode: wide
---

<PoweredBy
  packages={[
    { name: 'Base UI', url: 'https://base-ui.com/react/components/alert-dialog' },
    { name: 'Shadcn UI', url: 'https://ui.shadcn.com/docs/components/alert-dialog' },
  ]}
/>

### Installation

```package-install
npx shadcn@latest add @redpanda/alert-dialog
```

<ComponentPreview
  name="alert-dialog-demo"
  title="An alert dialog with cancel and continue buttons."
  description="An alert dialog with cancel and continue buttons."
/>

## Usage

### Basic Example

```tsx lineNumbers
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from '@/components/redpanda-ui/alert-dialog';

<AlertDialog>
  <AlertDialogTrigger render={<Button variant="destructive">Delete Account</Button>} />
  <AlertDialogContent>
    <AlertDialogHeader>
      <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
      <AlertDialogDescription>
        This action cannot be undone. This will permanently delete your account and remove your data from our servers.
      </AlertDialogDescription>
    </AlertDialogHeader>
    <AlertDialogFooter>
      <AlertDialogCancel>Cancel</AlertDialogCancel>
      <AlertDialogAction>Delete Account</AlertDialogAction>
    </AlertDialogFooter>
  </AlertDialogContent>
</AlertDialog>;
```

### Confirmation Dialog

```tsx lineNumbers
<AlertDialog>
  <AlertDialogTrigger render={<Button>Save Changes</Button>} />
  <AlertDialogContent>
    <AlertDialogHeader>
      <AlertDialogTitle>Save changes?</AlertDialogTitle>
      <AlertDialogDescription>
        This will update your profile information. You can change these settings later.
      </AlertDialogDescription>
    </AlertDialogHeader>
    <AlertDialogFooter>
      <AlertDialogCancel>Cancel</AlertDialogCancel>
      <AlertDialogAction>Save Changes</AlertDialogAction>
    </AlertDialogFooter>
  </AlertDialogContent>
</AlertDialog>
```

### Warning Dialog

```tsx lineNumbers
<AlertDialog>
  <AlertDialogTrigger render={<Button variant="outline">Reset Settings</Button>} />
  <AlertDialogContent>
    <AlertDialogHeader>
      <AlertDialogTitle>Reset all settings?</AlertDialogTitle>
      <AlertDialogDescription>
        This will restore all settings to their default values. Your custom configurations will be lost. This action
        cannot be undone.
      </AlertDialogDescription>
    </AlertDialogHeader>
    <AlertDialogFooter>
      <AlertDialogCancel>Keep Settings</AlertDialogCancel>
      <AlertDialogAction>Reset Settings</AlertDialogAction>
    </AlertDialogFooter>
  </AlertDialogContent>
</AlertDialog>
```

### Controlled State

```tsx lineNumbers
const [open, setOpen] = useState(false)

<AlertDialog open={open} onOpenChange={setOpen}>
  <AlertDialogTrigger render={<Button>Open Dialog</Button>} />
  <AlertDialogContent>
    <AlertDialogHeader>
      <AlertDialogTitle>Controlled Dialog</AlertDialogTitle>
      <AlertDialogDescription>
        This dialog's open state is controlled by React state.
      </AlertDialogDescription>
    </AlertDialogHeader>
    <AlertDialogFooter>
      <AlertDialogCancel onClick={() => setOpen(false)}>Cancel</AlertDialogCancel>
      <AlertDialogAction onClick={() => {
        // Perform action
        setOpen(false)
      }}>
        Confirm
      </AlertDialogAction>
    </AlertDialogFooter>
  </AlertDialogContent>
</AlertDialog>
```

## When to use

Use Alert Dialog for critical actions that require explicit user confirmation. This component blocks interaction with the rest of the application until resolved:

```mermaid
graph TD;
    A[❓ User wants to perform action] --> B{Is action destructive or irreversible?};

    B -->|Yes| C[✅ Use AlertDialog];
    B -->|No| D{Requires user confirmation?};

    D -->|Yes| E[⚠️ Use AlertDialog or Dialog];
    D -->|No| F[ℹ️ Perform action directly];

    G{Action affects important data?} -->|Yes| C;
    H{User needs to be warned?} -->|Yes| C;

    I{Need complex form inputs?} -->|Yes| J[⚠️ Use Dialog instead];
    I -->|No| K[✅ Use AlertDialog];

    L{Temporary notification?} -->|Yes| M[⚠️ Use Toast instead];
    L -->|No| N[⚠️ Use Alert for persistent info];

    classDef recommended fill:#4ade80,stroke:#22c55e,stroke-width:2px,color:#000;
    classDef discouraged fill:#fbbf24,stroke:#f59e0b,stroke-width:2px,color:#000;
    classDef decision fill:#60a5fa,stroke:#3b82f6,stroke-width:2px,color:#fff;
    classDef neutral fill:#9ca3af,stroke:#6b7280,stroke-width:2px,color:#fff;

    class C,K recommended;
    class E,J,M,N discouraged;
    class A,B,D,G,H,I,L decision;
    class F neutral;
```

**Use Alert Dialog when:**

- Confirming destructive actions (delete, reset, logout)
- Warning about irreversible changes
- Requiring explicit consent for important operations
- Preventing accidental data loss
- Blocking workflow until user makes a decision

**Don't use Alert Dialog when:**

- The action is easily reversible
- You need complex form inputs (use Dialog instead)
- Showing temporary notifications (use Toast instead)
- Displaying non-critical information (use Alert instead)
- The confirmation is optional or less critical

## Anatomy

The Alert Dialog component is built using Base UI primitives with a layered modal structure:

```
Modal Layer Stack:
┌─────────────────────────────────────────────────────┐
│ AlertDialogPortal (React Portal)                    │
│ ┌─────────────────────────────────────────────────┐ │
│ │ AlertDialogOverlay (backdrop)                   │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ AlertDialogContent (modal container)        │ │ │
│ │ │ ┌─────────────────────────────────────────┐ │ │ │
│ │ │ │ AlertDialogHeader                       │ │ │ │
│ │ │ │ ├── AlertDialogTitle                    │ │ │ │
│ │ │ │ └── AlertDialogDescription              │ │ │ │
│ │ │ └─────────────────────────────────────────┘ │ │ │
│ │ │ ┌─────────────────────────────────────────┐ │ │ │
│ │ │ │ AlertDialogBody (optional, scrolls)     │ │ │ │
│ │ │ └─────────────────────────────────────────┘ │ │ │
│ │ │ ┌─────────────────────────────────────────┐ │ │ │
│ │ │ │ AlertDialogFooter                       │ │ │ │
│ │ │ │ ├── AlertDialogCancel (outline button)  │ │ │ │
│ │ │ │ └── AlertDialogAction (primary button)  │ │ │ │
│ │ │ └─────────────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘

Trigger (outside modal):
AlertDialogTrigger → Opens the modal
```

**Component Hierarchy:**

1. **AlertDialog** (Root): Manages dialog state and provides context
2. **AlertDialogTrigger**: Button or element that opens the dialog
3. **AlertDialogPortal**: Renders modal outside normal DOM tree
4. **AlertDialogOverlay**: Semi-transparent backdrop (blocks interaction)
5. **AlertDialogContent**: Main modal container with animations
6. **AlertDialogHeader**: Contains title and description
7. **AlertDialogTitle**: Primary heading (required for accessibility)
8. **AlertDialogDescription**: Explanatory text
9. **AlertDialogBody**: Optional content between the header and footer, such as a list of affected resources or a type-to-confirm input. Scrolls when the content overflows
10. **AlertDialogFooter**: Contains action buttons
11. **AlertDialogCancel**: Cancel/dismiss action (typically outline style)
12. **AlertDialogAction**: Primary action button (typically destructive style)

**Key Features:**

- **Focus Management**: Automatically traps focus within dialog
- **Escape Handling**: Closes dialog when user presses Escape
- **Click Outside**: Closes dialog when clicking backdrop
- **Animations**: Smooth fade and scale transitions
- **Accessibility**: Proper ARIA attributes and screen reader support

## Examples

### Triggered from a Menu

<ComponentPreview
  name="alert-dialog-from-menu-demo"
  description="Alert dialog triggered from a dropdown menu item for inline destructive actions."
/>

### Close Confirmation

<ComponentPreview
  name="alert-dialog-close-confirmation-demo"
  description="Nested confirmation dialog guarding unsaved form input before closing."
/>

### Shared Across Multiple Triggers

<ComponentPreview
  name="alert-dialog-multiple-triggers-demo"
  description="A single alert dialog shared across multiple triggers with per-row payload context."
/>

### Destructive Confirmation

<ComponentPreview
  name="alert-dialog-destructive-demo"
  description="Destructive alert dialog for irreversible account or data deletion."
/>

### Sign-out Confirmation

<ComponentPreview
  name="alert-dialog-signout-demo"
  description="Sign-out confirmation with icon and supporting secondary description copy."
/>

### With a Body

Put content that isn't the title or description — affected resources, a type-to-confirm input, an error — in an `AlertDialogBody` between the header and footer, as you would a `DialogBody` in a [Dialog](/docs/dialog). The layout matches Dialog's: header, body, and footer each carry their own padding, dividers separate the body from the header and footer, and the body scrolls while the header and footer stay pinned. `AlertDialogContent` has no padding of its own, so content placed directly inside it, outside these three parts, sits flush against the dialog edge.

<ComponentPreview
  name="alert-dialog-with-body-demo"
  description="A type-to-confirm delete whose body lists the affected consumer groups between the header and footer."
/>

```tsx lineNumbers
<AlertDialogContent>
  <AlertDialogHeader>
    <AlertDialogTitle>Delete orders-v2?</AlertDialogTitle>
    <AlertDialogDescription>Every message in the topic is deleted.</AlertDialogDescription>
  </AlertDialogHeader>
  <AlertDialogBody>{/* affected resources, confirmation input, errors */}</AlertDialogBody>
  <AlertDialogFooter>
    <AlertDialogCancel>Cancel</AlertDialogCancel>
    <AlertDialogAction variant="destructive">Delete topic</AlertDialogAction>
  </AlertDialogFooter>
</AlertDialogContent>
```

## Props

<div className="flex flex-row gap-x-3">
  <ExternalLink href="https://base-ui.com/react/components/alert-dialog" text="Docs" />
  <ExternalLink href="https://base-ui.com/react/components/alert-dialog#api-reference" text="API Reference" />
</div>

### Component Props

#### AlertDialogBody

| Prop | Type | Default | Description |
| - | - | - | - |
| `padding?` | `'none' \| 'sm' \| 'md' \| 'lg'` | `'md'` | Padding around the body content. The inner content is wrapped so scroll shadows can sit flush against the body edges — set `padding` here rather than overriding via `className`, which targets the outer scroll container. |
| `spacing?` | `'none' \| 'sm' \| 'md' \| 'lg'` | `'md'` | Vertical gap between direct children of the body. |
| `scrollShadow?` | `boolean` | `true` | Show fading top/bottom shadows when the body overflows, cueing the user that there is more content above or below. |

## Keyboard interactions

| Key                                       | Action                                                        |
| ----------------------------------------- | ------------------------------------------------------------- |
| `Enter` / `Space` on `AlertDialogTrigger` | Opens the dialog and focuses the first focusable element.     |
| `Tab` / `Shift+Tab`                       | Cycles focus within the dialog — focus is trapped while open. |
| `Escape`                                  | Triggers the `Cancel` action (closes without confirming).     |
| `Enter` on `AlertDialogAction`            | Confirms the action.                                          |

## Accessibility

- `AlertDialog` is a specialised modal: unlike `Dialog`, it **cannot** be dismissed by clicking outside. The only exits
  are the explicit `AlertDialogAction`, `AlertDialogCancel`, and `Escape`.
- Always include an `AlertDialogTitle` and `AlertDialogDescription` — Base UI wires them to `aria-labelledby` and
  `aria-describedby` automatically.
- The dialog uses `role="alertdialog"`, which makes screen readers announce its contents immediately on open.
- Focus is trapped while open and returned to the trigger on close. Background content is inert.

## Controlled vs uncontrolled

Uncontrolled — the dialog owns open state:

```tsx lineNumbers
<AlertDialog onOpenChange={(open) => console.log('open:', open)}>
  <AlertDialogTrigger>Delete</AlertDialogTrigger>
  <AlertDialogContent>{/* ... */}</AlertDialogContent>
</AlertDialog>
```

Controlled — open the dialog programmatically (e.g. after a mutation error):

```tsx lineNumbers
const [open, setOpen] = useState(false);

async function handleDelete() {
  setOpen(true); // show confirmation before firing mutation
}

<AlertDialog open={open} onOpenChange={setOpen}>
  <AlertDialogContent>
    <AlertDialogHeader>
      <AlertDialogTitle>Delete topic?</AlertDialogTitle>
      <AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
    </AlertDialogHeader>
    <AlertDialogFooter>
      <AlertDialogCancel>Cancel</AlertDialogCancel>
      <AlertDialogAction onClick={confirmDelete}>Delete</AlertDialogAction>
    </AlertDialogFooter>
  </AlertDialogContent>
</AlertDialog>;
```

## Upgrading to the sectioned layout

`AlertDialog` now lays out like [Dialog](/docs/dialog). `AlertDialogContent` no longer pads its children (`p-6`, `gap-4`); `AlertDialogHeader` and `AlertDialogFooter` pad themselves, and `AlertDialogBody` holds everything between them. A dialog made of a header and a footer only needs no changes. Otherwise:

| Before                                                                                                         | Now                                                                         |
| -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| Content between the header and footer as a direct child of `AlertDialogContent`                                | Wrap it in `AlertDialogBody`, or it sits flush against the dialog edge.     |
| Inputs, lists, or alerts inside `AlertDialogDescription` or `AlertDialogHeader`                                | Move them into `AlertDialogBody`, and keep the description to text.         |
| A scroll wrapper (`min-h-0 overflow-y-auto`) around long content, or `overflow-y-auto` on `AlertDialogContent` | Drop it: `AlertDialogBody` scrolls while the header and footer stay pinned. |
| A full-bleed footer built from negative margins (`-mx-6 -mb-6 border-t …`)                                     | Drop the override: the footer pads itself, with a divider after a body.     |
| `p-*` or `gap-*` overrides on `AlertDialogContent`                                                             | Set `padding` and `spacing` on `AlertDialogBody` instead.                   |

## Credits

- We use [Base UI](https://base-ui.com/react/components/alert-dialog) for the alert dialog component.
- We take our inspiration from [Shadcn UI](https://ui.shadcn.com/docs/components/alert-dialog) for the alert dialog style.
