Skip to content
Redpanda UI
Esc
↑↓navigate↵open⌘Jpreview
Made by shadcn
Edit on GitHub

Alert Dialog

A modal dialog that interrupts the user with important content and expects a response.

Installation

bash
npx shadcn@latest add @redpanda/alert-dialog
bash
pnpm dlx shadcn@latest add @redpanda/alert-dialog
bash
yarn dlx shadcn@latest add @redpanda/alert-dialog
bash
bunx shadcn@latest add @redpanda/alert-dialog
bash
nubx shadcn@latest add @redpanda/alert-dialog
bash
aube dlx shadcn@latest add @redpanda/alert-dialog

Usage

Basic Example

tsx
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
<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
<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
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:

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:

plaintext
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

Close Confirmation

Shared Across Multiple Triggers

Destructive Confirmation

Sign-out Confirmation

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. 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.

tsx
<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

Component Props

AlertDialogBody

PropType
padding?'none' | 'sm' | 'md' | 'lg'

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.

Type'none' | 'sm' | 'md' | 'lg'
Default'md'
spacing?'none' | 'sm' | 'md' | 'lg'

Vertical gap between direct children of the body.

Type'none' | 'sm' | 'md' | 'lg'
Default'md'
scrollShadow?boolean

Show fading top/bottom shadows when the body overflows, cueing the user that there is more content above or below.

Typeboolean
Defaulttrue

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
<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
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. 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 for the alert dialog component.
  • We take our inspiration from Shadcn UI for the alert dialog style.

Recent changes

  • patchv1.2.0Pin shipped dependency floors to the version we develop against. Registry items now declare ranges like `^5.1.9` (the actual installed version) instead of collapsing to `^5.0.0`, so consumers start on the known-tested baseline while caret semantics still allow any compatible release within the same major.#133
  • minorv1.1.0Theme docs refresh, readability pass on semantic foregrounds, and consumer-facing Base UI regression fixes.#121
  • minorv1.1.0Bulk install experience and Dialog polish.#119
  • minorv1.0.0Post-Base-UI polish. Public API unchanged.#116
  • majorv1.0.0Migrate every Radix-based primitive to `@base-ui/react@^1.4.0` (Base UI).#114
See full history →

Last updated on

Was this page helpful?