AlertDialog
A modal confirmation dialog that requires a user response before continuing.
API Reference
Original primitive API
Behavior, accessibility details, and low-level props are documented by Base UI.
Basic
import { AlertDialog, AlertDialogTrigger, Button, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogCloseIcon, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction,} from "moduix";export function AlertDialogDemo() { return ( <AlertDialog> <AlertDialogTrigger render={<Button />}>Discard draft</AlertDialogTrigger> <AlertDialogContent> <AlertDialogHeader> <AlertDialogTitle>Discard draft?</AlertDialogTitle> <AlertDialogCloseIcon /> <AlertDialogDescription>You cannot undo this action.</AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel render={<Button variant="outline" />}>Cancel</AlertDialogCancel> <AlertDialogAction render={<Button />}>Discard</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> );}Full list of component variables available for project-level overrides.
| Property | Default | Description |
|---|---|---|
| --alert-dialog-action-bg | var(--color-primary) | Controls action button background. |
| --alert-dialog-action-bg-hover | var(--color-foreground) | Controls action button hover background. |
| --alert-dialog-action-border-color | var(--color-primary) | Controls action button border color. |
| --alert-dialog-action-color | var(--color-primary-foreground) | Controls action button text color. |
| --alert-dialog-backdrop-bg | var(--backdrop-bg, var(--color-overlay)) | Controls backdrop background. |
| --alert-dialog-backdrop-transition | var(--transition-default) | Controls backdrop transition timing. |
| --alert-dialog-bg | var(--color-popover) | Controls popup background color. |
| --alert-dialog-border-color | var(--color-border) | Controls popup border color. |
| --alert-dialog-border-width | var(--border-width-sm) | Controls popup border width. |
| --alert-dialog-cancel-bg | var(--alert-dialog-control-bg, var(--color-background)) | Controls cancel button background. |
| --alert-dialog-cancel-bg-hover | var(--alert-dialog-control-bg-hover) | Controls cancel button hover background. |
| --alert-dialog-cancel-border-color | var(--color-border) | Controls cancel button border color. |
| --alert-dialog-cancel-color | var(--alert-dialog-control-color, var(--color-foreground)) | Controls cancel button text color. |
| --alert-dialog-close-icon-bg | transparent | Controls close icon button background. |
| --alert-dialog-close-icon-bg-hover | var(--color-accent) | Controls close icon button hover background. |
| --alert-dialog-close-icon-color | var(--alert-dialog-muted-color) | Controls close icon button color. |
| --alert-dialog-close-icon-color-hover | var(--alert-dialog-color) | Controls close icon button hover color. |
| --alert-dialog-close-icon-focus-ring-color | var(--alert-dialog-focus-ring-color) | Controls close icon focus ring color. |
| --alert-dialog-close-icon-glyph-size | 0.75rem | Controls default close icon glyph size. |
| --alert-dialog-close-icon-radius | var(--radius-md) | Controls close icon button border radius. |
| --alert-dialog-close-icon-size | 1.75rem | Controls close icon button size. |
| --alert-dialog-color | var(--color-popover-foreground) | Controls popup text color. |
| --alert-dialog-content-margin | var(--spacing-4) 0 0 | Controls body top margin. |
| --alert-dialog-control-bg | var(--color-background) | Controls control background. |
| --alert-dialog-control-bg-hover | var(--color-accent) | Controls control hover background. |
| --alert-dialog-control-border-color | var(--color-border) | Controls control border color. |
| --alert-dialog-control-border-width | var(--border-width-sm) | Controls control border width. |
| --alert-dialog-control-color | var(--color-foreground) | Controls control text color. |
| --alert-dialog-control-font-size | var(--text-md) | Controls control font size. |
| --alert-dialog-control-height | var(--size-lg) | Controls control minimum height. |
| --alert-dialog-control-line-height | var(--line-height-text-md) | Controls control line height. |
| --alert-dialog-control-padding-x | 0.875rem | Controls control horizontal padding. |
| --alert-dialog-control-padding-y | 0.5rem | Controls control vertical padding. |
| --alert-dialog-control-radius | var(--radius-md) | Controls control border radius. |
| --alert-dialog-description-color | var(--alert-dialog-muted-color) | Controls description and body text color. |
| --alert-dialog-description-font-size | var(--text-md) | Controls description and body font size. |
| --alert-dialog-description-line-height | var(--line-height-text-md) | Controls description and body line height. |
| --alert-dialog-focus-ring-color | var(--color-ring) | Controls focus ring color. |
| --alert-dialog-focus-ring-width | var(--alert-dialog-control-border-width) | Controls focus ring width. |
| --alert-dialog-footer-gap | var(--spacing-2) | Controls footer actions gap. |
| --alert-dialog-footer-margin-top | var(--spacing-6) | Controls footer top margin. |
| --alert-dialog-header-gap | var(--spacing-1) | Controls header gap. |
| --alert-dialog-max-width | calc(100vw - var(--spacing-8)) | Controls popup max width. |
| --alert-dialog-muted-color | var(--color-muted-foreground) | Controls muted text color. |
| --alert-dialog-padding | var(--spacing-6) | Controls popup padding. |
| --alert-dialog-radius | var(--radius-lg) | Controls popup border radius. |
| --alert-dialog-scale | var(--scale-popup) | Controls enter/exit scale. |
| --alert-dialog-shadow | var(--shadow-lg) | Controls popup shadow. |
| --alert-dialog-title-color | var(--alert-dialog-color) | Controls title text color. |
| --alert-dialog-title-font-size | var(--text-lg) | Controls title font size. |
| --alert-dialog-title-font-weight | var(--weight-semibold) | Controls title font weight. |
| --alert-dialog-title-line-height | var(--line-height-text-lg) | Controls title line height. |
| --alert-dialog-transition | var(--transition-default) | Controls popup transition timing. |
| --alert-dialog-trigger-color | var(--color-destructive) | Controls trigger text color. |
| --alert-dialog-viewport-padding | var(--spacing-4) | Controls viewport padding. |
| --alert-dialog-width | 24rem | Controls the popup width. |
Interactive variables scoped for docs preview without changing size scale tokens.
| Property | Value | Default | Description |
|---|---|---|---|
| --alert-dialog-backdrop-bg | var(--backdrop-bg, var(--color-overlay)) | Controls backdrop. | |
| --alert-dialog-bg | var(--color-popover) | Controls the popup background color. | |
| --alert-dialog-border-color | var(--color-border) | Controls popup border color. | |
| --alert-dialog-color | var(--color-popover-foreground) | Controls popup text color. | |
| --alert-dialog-description-color | var(--alert-dialog-muted-color) | Controls description and body text color. | |
| --alert-dialog-radius | var(--radius-lg) | Controls the popup border radius. | |
| --alert-dialog-shadow | var(--shadow-lg) | Controls popup shadow. | |
| --alert-dialog-title-color | var(--alert-dialog-color) | Controls title text color. |
Anatomy
AlertDialog is built around a root state container and a content surface that renders the
portal, backdrop, and viewport for you. Keep title, description, and actions inside
AlertDialogContent so focus management and accessibility labeling stay connected.
AlertDialog
├─ AlertDialogTrigger
└─ AlertDialogContent
├─ AlertDialogHeader
│ ├─ AlertDialogTitle
│ ├─ AlertDialogCloseIcon (optional)
│ └─ AlertDialogDescription
├─ AlertDialogBody (optional)
└─ AlertDialogFooter
├─ AlertDialogCancel
└─ AlertDialogAction<AlertDialog>
<AlertDialogTrigger render={<Button />}>Discard draft</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Discard draft?</AlertDialogTitle>
<AlertDialogCloseIcon />
<AlertDialogDescription>You cannot undo this action.</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel render={<Button variant="outline" />}>Cancel</AlertDialogCancel>
<AlertDialogAction render={<Button />}>Discard</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>| Part | Role |
|---|---|
AlertDialog | Root state machine. Manages open state, controlled/uncontrolled behavior, and close interactions. |
AlertDialogTrigger | Opens the confirmation dialog. Usually rendered as a button via render. |
AlertDialogContent | Main dialog surface. Also renders portal/backdrop/viewport and exposes escape hatches via props. |
AlertDialogHeader | Groups heading content for the top area of the popup. |
AlertDialogTitle | Required accessible title for the dialog. |
AlertDialogDescription | Optional supporting text that explains the consequence of the action. |
AlertDialogCloseIcon | Optional dismiss button in the header; accepts custom icon children. |
AlertDialogBody | Optional scrollable/content area between header and footer for longer details. |
AlertDialogFooter | Layout container for decision actions. |
AlertDialogCancel | Secondary action that closes without confirming. |
AlertDialogAction | Primary confirmation action; closes after activation unless custom logic keeps it open. |
portal slot | Mount layer outside normal layout flow. Useful for stacking and isolating dialog rendering roots. |
backdrop slot | Overlay behind the popup. Dim background content and communicate modal focus. |
viewport slot | Alignment container around the popup. Controls placement and outer spacing behavior. |
Use default slot styling in most cases. Customize portal when integrating with a specific
mount container or layered app shell, backdrop for brand-specific overlay tone/interaction,
and viewport when placement rules differ (for example top-aligned or edge-biased dialogs).
Composition
Use AlertDialog for root state and behavior props such as open, defaultOpen,
onOpenChange, triggerId, defaultTriggerId, actionsRef, and handle. Triggers support
Base UI handle, payload, id, nativeButton, render, state-based className, and
state-based style props.
className styles the visible popup. classNames styles the internal service slots that are
hidden from the default composition. AlertDialogContent accepts the popup props from Base UI,
including initialFocus, finalFocus, render, state-based className, and state-based style.
Use container, slotProps, and withBackdrop={false} when you need service-slot escape hatches:
<AlertDialogContent
className={styles.popup}
classNames={{
portal: styles.portal,
backdrop: styles.backdrop,
viewport: styles.viewport,
}}
slotProps={{
portal: { keepMounted: true },
backdrop: { forceRender: true },
viewport: { render: <div /> },
}}
/>The service slots still expose the Base UI data attributes on their rendered elements: backdrop,
viewport, and popup receive open/closed and transition attributes; viewport and popup also receive
nested-dialog attributes. The popup also provides Base UI's --nested-dialogs variable for nested
dialog styling.
Examples
Controlled
Control the open state from React when the dialog needs to coordinate with other UI.
import { AlertDialog, AlertDialogTrigger, Button, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction,} from "moduix";import { useState } from "react";export function ControlledAlertDialogDemo() { const [open, setOpen] = useState(false); return ( <AlertDialog open={open} onOpenChange={setOpen}> <AlertDialogTrigger render={<Button />}>Open controlled dialog</AlertDialogTrigger> <AlertDialogContent> <AlertDialogHeader> <AlertDialogTitle>Publish changes?</AlertDialogTitle> <AlertDialogDescription> This will make the latest version visible to all users. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel render={<Button variant="outline" />}> Back to editing </AlertDialogCancel> <AlertDialogAction render={<Button />}>Publish</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> );}Handle
Use createAlertDialogHandle when a confirmation is opened from detached triggers or from
imperative event handlers. Pass payload to detached triggers when the dialog copy depends on the
source action.
import { createAlertDialogHandle, AlertDialogTrigger, Button, AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction,} from "moduix";import { useMemo, Fragment } from "react";export function AlertDialogHandleDemo() { const alertDialogHandle = useMemo(() => createAlertDialogHandle(), []); return ( <Fragment> <AlertDialogTrigger handle={alertDialogHandle} render={<Button variant="outline" />}> Open from detached trigger </AlertDialogTrigger> <Button type="button" onClick={() => alertDialogHandle.open(null)}> Open programmatically </Button> <AlertDialog handle={alertDialogHandle}> <AlertDialogContent> <AlertDialogHeader> <AlertDialogTitle>Delete workspace?</AlertDialogTitle> <AlertDialogDescription> This alert dialog is connected via createAlertDialogHandle(). </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel render={<Button variant="outline" />}>Cancel</AlertDialogCancel> <AlertDialogAction render={<Button />}>Delete</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> </Fragment> );}Scrollable Content
Place ScrollArea inside AlertDialogBody for longer confirmation details.
import { AlertDialog, AlertDialogTrigger, Button, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogCloseIcon, AlertDialogDescription, AlertDialogBody, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, ScrollArea,} from "moduix";export function ScrollableAlertDialogDemo() { return ( <AlertDialog> <AlertDialogTrigger render={<Button />}>Delete project</AlertDialogTrigger> <AlertDialogContent> <AlertDialogHeader> <AlertDialogTitle>Delete project?</AlertDialogTitle> <AlertDialogCloseIcon /> <AlertDialogDescription> This removes all deployment environments and API keys. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogBody className={styles.scrollBody}> <ScrollArea className={styles.scrollArea} classNames={{ content: styles.scrollContent }} > {sections.map((item) => ( <section key={item.title}> <h3>{item.title}</h3> <p>{item.body}</p> </section> ))} </ScrollArea> </AlertDialogBody> <AlertDialogFooter> <AlertDialogCancel render={<Button variant="outline" />}>Cancel</AlertDialogCancel> <AlertDialogAction render={<Button />}>Delete permanently</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> );}.scrollBody { height: min(26rem, calc(100dvh - var(--spacing-10))); overflow: hidden;}.scrollArea { height: 100%; min-height: 0;}.scrollContent { display: grid; gap: var(--spacing-4); padding-right: var(--spacing-5);}const sections = [ { title: 'What this surface is for', body: 'Use temporary surfaces for focused tasks that should keep users in the current page context.', }, { title: 'Keyboard and focus', body: 'Tab and Shift+Tab should stay predictable while Escape or explicit controls request close.', }, { title: 'Viewport overflow', body: 'Keep the container visible and place long content in a dedicated scrollable inner region.', }, { title: 'Close affordances', body: 'Always provide an explicit close action when the surface can be dismissed by the user.', }, { title: 'Mobile ergonomics', body: 'Keep touch targets reachable and avoid cramped headers on narrow viewports.', }, { title: 'Persistent panels', body: 'For persistent workflows, keep the important controls fixed and scroll only the supporting content.', }, { title: 'Status updates', body: 'After completion, close the surface and show an inline confirmation or toast.', }, { title: 'Error handling', body: 'When an action fails, keep the user in context and show the recovery step near the failed control.', }, { title: 'Long descriptions', body: 'Dense explanatory copy should remain readable without pushing primary actions out of reach.', }, { title: 'Scrolling feedback', body: 'Visible scrollbars, fades, or edge states help users understand that additional content is available.', }, { title: 'Footer behavior', body: 'Footer actions should stay stable when the user reviews long terms, warnings, or settings.', }, { title: 'Review checklist', body: 'Use repeated sections to test keyboard scrolling, wheel scrolling, touch scrolling, and drag gestures.', }, { title: 'Final confirmation', body: 'The final section should be reachable without layout jumps or hidden content at the bottom edge.', },];Custom Close Icon
Pass children to AlertDialogCloseIcon to use any icon from your application or icon library.
import { AlertDialog, AlertDialogTrigger, Button, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogCloseIcon, CloseLineIcon, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction,} from "moduix";export function CustomCloseIconAlertDialogDemo() { return ( <AlertDialog> <AlertDialogTrigger render={<Button />}>Archive workspace</AlertDialogTrigger> <AlertDialogContent> <AlertDialogHeader> <AlertDialogTitle>Archive workspace?</AlertDialogTitle> <AlertDialogCloseIcon aria-label="Close archive dialog" className={styles.customCloseIcon} > <CloseLineIcon /> </AlertDialogCloseIcon> <AlertDialogDescription> Team members will lose access until the workspace is restored. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel render={<Button variant="outline" />}>Cancel</AlertDialogCancel> <AlertDialogAction render={<Button />}>Archive</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> );}.customCloseIcon { --alert-dialog-close-icon-color: var(--color-muted-foreground);}Custom Styles
Use className for the popup and classNames for the automatically rendered portal, backdrop,
and viewport.
import { AlertDialog, AlertDialogTrigger, Button, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction,} from "moduix";export function CustomStylesAlertDialogDemo() { return ( <AlertDialog> <AlertDialogTrigger render={<Button />}>Reset environment</AlertDialogTrigger> <AlertDialogContent className={styles.customPopup} classNames={{ portal: styles.customPortal, backdrop: styles.customBackdrop, viewport: styles.customViewport, }} > <AlertDialogHeader> <AlertDialogTitle>Reset environment?</AlertDialogTitle> <AlertDialogDescription> All runtime variables will return to their default values. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel render={<Button variant="outline" />}>Cancel</AlertDialogCancel> <AlertDialogAction render={<Button />}>Reset</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> );}.customPortal { pointer-events: auto;}.customBackdrop { background-color: rgb(15 23 42 / 0.56);}.customViewport { align-items: start; padding-top: var(--spacing-10);}.customPopup { --alert-dialog-width: 28rem; --alert-dialog-radius: var(--radius-md);}