Components

Alert Dialog

A modal dialog that interrupts the user with important content and expects an explicit confirm-or-cancel response before proceeding.

Basic usage

Wrap a trigger and content. Radix manages the open state, focus trap, and dismissal for you.

Destructive action

For irreversible actions, open from a destructive button and restyle AlertDialogAction by re-running buttonVariants. Do not hand-write the red: --destructive is the only red pinned across both palettes that carries a foreground colour.

ConfirmDialog composite

The package ships ConfirmDialog, a Tier 2 composite that wraps this component so every app asks the same way. It adds the icon slot, the destructive treatment, and an async onConfirm: while the promise is in flight the confirm button is disabled and the dialog refuses to close, so a slow API cannot be deleted twice. A throw keeps the dialog open and is handed to onError. The confirm, cancel and pending labels are all yours to set — the built-in "Đang xử lý…" is Vietnamese, so pass pendingLabel in an English app.

AlertDialog Props

PropTypeDefaultDescription
openbooleanControlled open state of the dialog. Omit to let Radix manage it internally.
defaultOpenbooleanfalseOpen state when initially rendered, for uncontrolled usage.
onOpenChange(open: boolean) => voidCalled when the open state changes (trigger, cancel, action, or Escape).
childrenrequiredReact.ReactNodeTrigger and content. There is no modal prop — an alert dialog is always modal.

Parts

PropTypeDefaultDescription
AlertDialogTriggerAlertDialogPrimitive.TriggerThe control that opens the dialog. Use asChild to render your own Button.
AlertDialogPortalAlertDialogPrimitive.PortalPortal target. AlertDialogContent renders one already — reach for it only for a custom shell.
AlertDialogOverlayAlertDialogPrimitive.OverlayDimmed backdrop (bg-ink/60, dark:bg-ink/80, backdrop-blur). Also rendered for you by AlertDialogContent.
AlertDialogContentAlertDialogPrimitive.ContentThe modal panel: portal + overlay + card surface. Fixed at sm:max-w-lg — unlike Dialog it takes no size prop and shows no corner close button.
AlertDialogHeaderdivflex flex-col gap-2, centred on mobile and left-aligned from sm up.
AlertDialogTitleAlertDialogPrimitive.TitleAccessible name for the panel. Required — Radix warns when it is missing.
AlertDialogDescriptionAlertDialogPrimitive.DescriptionSupporting text linked to the panel via aria-describedby.
AlertDialogFooterdivActions row: stacked and reversed on mobile, right-aligned from sm up.
AlertDialogActionAlertDialogPrimitive.ActionConfirming button. Pre-styled with buttonVariants() — the default gold button; closes the dialog on click.
AlertDialogCancelAlertDialogPrimitive.CancelDismissing button. Pre-styled with buttonVariants({ variant: "outline" }); receives initial focus and closes the dialog.
classNamestringAdditional Tailwind classes merged onto any part with cn().

ConfirmDialog Props

PropTypeDefaultDescription
titlerequiredReactNodeHeadline of the confirmation, rendered as AlertDialogTitle.
onConfirmrequired() => void | Promise<void>Runs on confirm. Return a promise and the dialog stays open in a pending state until it settles — closing first and calling the API after is the reliable way to get a double delete.
descriptionReactNodeSupporting text under the title.
childrenReactNodeExtra content between header and footer — the list of affected records, a reason field.
triggerReactNodeElement that opens the dialog; wrapped in AlertDialogTrigger asChild.
iconComponentType<{ className?: string }>Optional leading icon, shown in a tinted square (destructive uses bg-destructive/15 with the -ink step).
variant'default' | 'destructive''default'destructive paints the confirm button red — use it for delete and revoke.
confirmLabelstring'Xác nhận'Confirm button text. The package default is Vietnamese — pass English here.
cancelLabelstring'Hủy'Cancel button text. Vietnamese by default, same as above.
pendingLabelstring'Đang xử lý…'Confirm button text while an async onConfirm is in flight. Vietnamese by default — override it or the button flips language mid-action.
confirmDisabledbooleanfalseLocks the confirm button, e.g. until the user has typed the record name.
openbooleanControlled open state. Leave it out and the dialog manages its own, paired with trigger.
onOpenChange(open: boolean) => voidCalled when the dialog opens or closes. Closing is ignored while onConfirm is pending.
onError(error: unknown) => voidReceives a throw from onConfirm so the app can raise a toast; without it the error is logged. The dialog stays open either way so the user can retry.
classNamestringMerged onto AlertDialogContent.

Accessibility

  • Built on Radix Alert Dialog: the content is rendered with role="alertdialog" and focus is trapped inside while open.
  • AlertDialogTitle and AlertDialogDescription are wired to aria-labelledby and aria-describedby automatically — always include a Title.
  • Unlike a regular dialog, clicking the overlay does nothing: the user has to pick Cancel or the action. Escape still closes, which counts as cancelling.
  • The Cancel button receives initial focus, and focus returns to the trigger when the dialog closes.
  • There is no corner close button and no size prop — the panel is always sm:max-w-lg. Reach for Dialog when the user should be able to walk away.