AlertDialog
alert-dialogRequests confirmation for consequential actions in a blocking accessible dialog.
Usage
Basic usage
Forced confirmation before destruction/irreversible operation: default does not respond to point mask / Esc closed, must explicitly click button decision.
<AlertDialog>
<AlertDialogTrigger>Delete item</AlertDialogTrigger>
<AlertDialogContent title="Delete project?" description="This operation is irreversible and the project data will be permanently deleted.">
<AlertDialogClose>Cancel</AlertDialogClose>
<AlertDialogClose>Delete</AlertDialogClose>
</AlertDialogContent>
</AlertDialog>Only description without description
description can be omitted, leaving just the title as a11y label.
<AlertDialog>
<AlertDialogTrigger>Log out</AlertDialogTrigger>
<AlertDialogContent title="Confirm to log out?">
<AlertDialogClose>Cancel</AlertDialogClose>
<AlertDialogClose>Exit</AlertDialogClose>
</AlertDialogContent>
</AlertDialog>Body content and status icon
body takes block-level content, such as a summary card of the object being deleted, and renders below the description and above the action row. description accepts phrasing content only, because it renders as a <p>. icon sits to the left of the title row; the caller supplies its color token.
<AlertDialogContent
icon={<WarnIcon className="text-danger" />}
title="Delete this contract template?"
description="It will be removed from the contract library, the public library, and every company library at once. This cannot be undone."
body={
<div className="rounded-[var(--radius)] border border-border p-3">
<div className="font-medium">Guanya / Full-time employment contract</div>
<div className="text-xs text-muted-foreground">copy-guanya-full-time-employment-contract.docx</div>
</div>
}
>
<AlertDialogClose>Cancel</AlertDialogClose>
<AlertDialogClose>Delete permanently</AlertDialogClose>
</AlertDialogContent>Open by default
Use uncontrolled defaultOpen to expand the dialog box initially (for controlled use, use open + onOpenChange).
<AlertDialog defaultOpen>
<AlertDialogTrigger>Empty Recycle Bin</AlertDialogTrigger>
<AlertDialogContent title="Empty the Recycle Bin?" description="28 of the files will be permanently deleted and cannot be recovered.">
<AlertDialogClose>Cancel</AlertDialogClose>
<AlertDialogClose>Clear</AlertDialogClose>
</AlertDialogContent>
</AlertDialog>When to use
Use AlertDialog before a destructive or irreversible action, such as deletion, clearing data, or leaving unsaved work. Overlay clicks and Escape deliberately do not close it; the user must choose Cancel or Confirm. Use Dialog for a normally dismissible dialog or Modal for an imperative one-line confirmation.
Import
import { AlertDialog, AlertDialogTrigger, AlertDialogClose, AlertDialogContent } from "@hulianui/ui"Props
AlertDialog, AlertDialogTrigger, and AlertDialogClose are thin wrappers around their Base UI AlertDialog primitives. Trigger and Close accept className or render to supply an element. AlertDialogContent adds HulianUI styling:
| Name | Type | Default | Description |
|---|---|---|---|
AlertDialogContent.className | string | - | Content-container class name. |
Events
| Event | Type | Description |
|---|---|---|
AlertDialog.onOpenChange | (open: boolean) => void | Called when the open state changes; forwarded to Base UI AlertDialog Root. |
Slots
| Slot | Type | Description |
|---|---|---|
AlertDialogContent.title * | ReactNode | Required title and accessible label. |
AlertDialogContent.description | ReactNode | Supporting copy. Phrasing content only (text, span, strong, a) because it renders as a <p>; put block-level content in body. |
AlertDialogContent.body | ReactNode | Main content, rendered below description and above the action area. It is not wrapped in a <p>, so block-level content such as a summary card or an affected-items list is valid here. |
AlertDialogContent.icon | ReactNode | Status icon on the left of the title row. The component only handles flex alignment; supply the color yourself (text-danger for destructive actions, text-warning for warnings). |
AlertDialogContent.children | ReactNode | Bottom action area for Cancel and Confirm buttons; use AlertDialogClose for cancellation. |
Example
<AlertDialog>
<AlertDialogTrigger className="…">Delete project</AlertDialogTrigger>
<AlertDialogContent title="Delete project?" description="This cannot be undone and project data will be permanently removed.">
<AlertDialogClose className="…">Cancel</AlertDialogClose>
<AlertDialogClose className="…">Delete</AlertDialogClose>
</AlertDialogContent>
</AlertDialog>With body content and a status icon:
<AlertDialog>
<AlertDialogTrigger className="…">Delete contract template</AlertDialogTrigger>
<AlertDialogContent
icon={<WarnIcon className="text-danger" />}
title="Delete contract template?"
description="It is removed from the shared, public, and per-company libraries and cannot be restored."
body={
<div className="rounded-[var(--radius)] border border-border p-3">
<div className="font-medium">Full-time employment contract</div>
<div className="text-xs text-muted-foreground">full-time-contract-copy.docx</div>
</div>
}
>
<AlertDialogClose className="…">Cancel</AlertDialogClose>
<AlertDialogClose className="…">Delete permanently</AlertDialogClose>
</AlertDialogContent>
</AlertDialog>Usage guidelines
- `description` accepts phrasing content only (text,
<span>,<strong>,<a>). It renders throughAlertDialog.Descriptionas a<p>, so a<div>,<ul>, or card inside it is invalid nesting: the browser closes the<p>early and React reports a hydration mismatch. Put block-level content in `body` instead of working around it with<span className="block">. childrenis the bottom action area (ajustify-endrow of buttons), not the main content. Content placed there is squeezed in beside the buttons. Dialog is the other way round, wherechildrenis the content andfooterholds the actions, so the two are not interchangeable.icononly handles alignment with the title and description and carries no color. Passtext-dangerfor destructive actions ortext-warningfor warnings; otherwise it inherits the normal foreground color.- The popup has no internal scroll area, unlike Dialog with its
max-hand scrolling content, so longbodycontent pushes the popup past the viewport. Needing long content means the interaction is no longer a forced decision, so use Dialog instead. - Ignoring overlay clicks and Escape is intentional forced-decision behavior. Use Dialog when lightweight dismissal is appropriate.
- A cancel button must use
AlertDialogCloseto close the dialog. Confirmation commonly uses it as well and performs the operation fromonClick.