AlertDialog.Root
design-system-components-alertdialog · ../packages/ui/src/alert-dialog/stories/index.story.tsx
A badge component for displaying labels with semantic intent.
Prop types
4 prop types
Component: ../packages/ui/src/badge/badge.tsx::Badge
Props:
/**
* The text to display in the badge.
*/
children: string
/**
* CSS class name to apply to the component.
*/
className?: string
/**
* The semantic intent of the badge, communicating its meaning through color.
*
* @default "none"
*/
intent?: | 'high'
| 'medium'
| 'low'
| 'stable'
| 'informational'
| 'draft'
| 'none' = 'none'
/**
* Replaces the component's default HTML element using a given React
* element, or a function that returns a React element.
*/
render?: | ComponentRenderFn< HTMLAttributesWithRef >
| React.ReactElement< Record< string, unknown > >
Imports
import { AlertDialog, Text } from "@wordpress/ui";
import { Menu } from "@base-ui/react/menu";
Default
story ok
Standard confirmation dialog for reversible actions. The dialog can be dismissed via Escape key or the cancel/confirm buttons. Backdrop click is blocked.
const Default = () => <AlertDialog.Root>(<>
<AlertDialog.Trigger>Move to trash</AlertDialog.Trigger>
<AlertDialog.Popup
title="Move to trash?"
description="This post will be moved to trash. You can restore it later."
/>
</>)</AlertDialog.Root>;
Irreversible
story ok
Confirmation dialog for irreversible actions that cannot be undone. The confirm button uses error/danger coloring.
const Irreversible = () => <AlertDialog.Root>(<>
<AlertDialog.Trigger>Delete permanently</AlertDialog.Trigger>
<AlertDialog.Popup
intent="irreversible"
title="Delete permanently?"
description="This action cannot be undone. All data will be lost."
confirmButtonText="Delete permanently"
/>
</>)</AlertDialog.Root>;
Custom Labels
story ok
Example with custom button labels for both confirm and cancel buttons.
const CustomLabels = () => <AlertDialog.Root>(<>
<AlertDialog.Trigger>Send feedback</AlertDialog.Trigger>
<AlertDialog.Popup
title="Send feedback?"
description="Your feedback helps us improve. Would you like to send it now?"
confirmButtonText="Send feedback"
cancelButtonText="Not now"
/>
</>)</AlertDialog.Root>;
With Custom Content
story ok
Use `children` to render custom content between the description and the action buttons. The `description` should be self-contained for accessibility (`aria-describedby`); `children` adds supplementary detail.
const WithCustomContent = () => <AlertDialog.Root>(<>
<AlertDialog.Trigger>Remove pages</AlertDialog.Trigger>
<AlertDialog.Popup
title="Remove 3 pages?"
description="These pages will be moved to trash."
confirmButtonText="Delete pages"
>
<ul
style={ {
margin: 0,
paddingInlineStart: 'var(--wpds-dimension-gap-lg)',
} }
>
<Text render={ <li /> }>About us</Text>
<Text render={ <li /> }>Contact</Text>
<Text render={ <li /> }>Privacy policy</Text>
</ul>
</AlertDialog.Popup>
</>)</AlertDialog.Root>;
Menu Trigger
story ok
Example showing composition with a menu. The `AlertDialog.Trigger` is composed with Base UI's `Menu.Item` using the `render` prop, allowing the menu item to directly trigger the alert dialog. Note: the example currently uses the `Menu` component from BaseUI, although consumers should not use BaseUI directly and instead use the DS `Menu` component (not ready yet).
const MenuTrigger = () => {
const [ menuOpen, setMenuOpen ] = useState( false );
return (
<>
<Menu.Root onOpenChange={ setMenuOpen } open={ menuOpen }>
<Menu.Trigger>Actions ▾</Menu.Trigger>
<Menu.Portal>
<Menu.Positioner>
<Menu.Popup style={ menuPopupStyles }>
<Menu.Item style={ menuItemStyles }>
Edit
</Menu.Item>
<AlertDialog.Root
onConfirm={ () => {
setMenuOpen( false );
action( 'onConfirm' )();
} }
>
<Menu.Item
render={
<AlertDialog.Trigger
// Quick fix to remove `button`-specific styles.
// This shouldn't be an issue once we use the DS `Menu`
// component, which will come with item styles.
render={ <div /> }
/>
}
style={ menuItemStyles }
closeOnClick={ false }
>
Delete...
<AlertDialog.Popup
intent="irreversible"
title="Delete permanently?"
description="This action cannot be undone. All data will be lost."
confirmButtonText="Delete permanently"
/>
</Menu.Item>
</AlertDialog.Root>
</Menu.Popup>
</Menu.Positioner>
</Menu.Portal>
</Menu.Root>
</>
);
};
Async Confirm
story ok
Async confirm flow. The consumer returns a promise from `onConfirm`. The dialog automatically manages the pending state: buttons are disabled and a spinner appears on the confirm button. Toggle between success and failure to test both outcomes. On failure, the consumer catches the error and returns `{ close: false, error: '...' }`. The component displays the message below the action buttons and announces it to screen readers. The error is automatically cleared on the next confirm attempt or when the dialog reopens.
const AsyncConfirm = () => {
const [ shouldFail, setShouldFail ] = useState( false );
const successId = useId();
const failureId = useId();
return (
<>
<fieldset>
<legend>Async task outcome</legend>
<label htmlFor={ successId }>
<input
id={ successId }
type="radio"
name="async-outcome"
checked={ ! shouldFail }
onChange={ () => setShouldFail( false ) } />Success (closes dialog)
</label>
<label htmlFor={ failureId } style={ { marginInlineStart: 12 } }>
<input
id={ failureId }
type="radio"
name="async-outcome"
checked={ shouldFail }
onChange={ () => setShouldFail( true ) } />Failure (dialog stays open, shows error)
</label>
</fieldset>
<br />
<AlertDialog.Root
onConfirm={ async () => {
action( 'onConfirm' )();
try {
await sleep( 2000 );
if ( shouldFail ) {
throw new Error( 'Task failed' );
}
} catch {
return {
close: false,
error: 'Something went wrong. Please try again.',
};
}
return undefined;
} }>
<AlertDialog.Trigger>Delete permanently
</AlertDialog.Trigger>
<AlertDialog.Popup
intent="irreversible"
title="Delete permanently?"
description="This action cannot be undone. All data will be lost."
confirmButtonText="Delete permanently" />
</AlertDialog.Root>
</>
);
};
Controlled
story ok
The `AlertDialog.Trigger` element is not necessary when the open state is controlled externally. This is useful when the dialog needs to be opened from code or from a non-standard trigger element.
const Controlled = () => {
const [ isOpen, setIsOpen ] = useState( false );
return (
<>
<button onClick={ () => setIsOpen( true ) }>Open Dialog</button>
<AlertDialog.Root
open={ isOpen }
onOpenChange={ ( open, eventDetails ) => {
setIsOpen( open );
args.onOpenChange?.( open, eventDetails );
} }>
<AlertDialog.Popup
title="Move to trash?"
description="This post will be moved to trash. You can restore it later." />
</AlertDialog.Root>
</>
);
};