Alert Dialog
Confirmation modal.
Usage
Use this when the user must decide before continuing and one outcome is destructive. Title is not optional — Bits points the dialog's aria-labelledby at it, so leaving it out ships a dialog with no accessible
name.
Action does not close
Cancel closes the dialog. Action does not. This is deliberate, and it is the one thing people get wrong here.
The reason is that your destructive operation is usually async and can fail. If Action closed the dialog for you, a failed delete would leave the user staring at a dismissed dialog with no idea whether it worked. So closing is yours to decide: close after it succeeds, or keep it open and show the error.
Close on success, stay open on failure — that is why the primitive leaves it to you.
Alert Dialog vs Dialog
The differences are behavioural, not decorative — which is why you cannot get here by styling a Dialog differently:
role="alertdialog", so it is announced as an interruption.- Clicking the backdrop does not dismiss it. Bits omits
onInteractOutsideon Content, so a stray click cannot resolve a destructive choice. - Cancel takes initial focus, so pressing Enter never destroys anything.
If nothing is being destroyed and the user can just walk away, you want Dialog. Reaching for Alert Dialog for ordinary content trains people to dismiss warnings without reading them.
Writing the copy
The component is the easy part. Label the buttons with the verb, not OK and Cancel — "Delete project" and "Keep project"
tell the user what each button does without re-reading anything. And put the consequence in the
description: what disappears, and whether it can be undone. "Are you sure?" is not a description;
it just moves the question back to the user.
Props
AlertDialog.Root
| Prop | Type | Default |
|---|---|---|
children bits-ui | Snippet<[]> | undefined | — |
onOpenChange bits-ui A callback that is called when the popover's open state changes. | OnChangeFn<boolean> | undefined | — |
onOpenChangeComplete bits-ui A callback called when the dialog finishes opening/closing animations. | OnChangeFn<boolean> | undefined | — |
open bits-ui The open state of the dialog. | boolean | undefined | — |
AlertDialog.Content
| Prop | Type | Default |
|---|---|---|
class Extra classes merged onto the panel. | string | — |
child bits-ui | Snippet<[DialogContentSnippetProps & { props: Record<string, unknown>; }]> | undefined | — |
children bits-ui | Snippet<[]> | undefined | — |
escapeKeydownBehavior bits-ui Escape behavior type. `close`: Closes the element immediately. `defer-otherwise-close`: Delegates the action to its parent component that has an escape keydown handler. If no parent is found, it closes the element. `defer-otherwise-ignore`: Delegates the action to the parent element. If no parent is found, nothing is done. `ignore`: Prevents the element from closing and also blocks the parent element from closing in response to an escape key press. | EscapeBehaviorType | undefined | `close` |
forceMount bits-ui Whether to force mount the component. | boolean | undefined | — |
id bits-ui | string | undefined | — |
interactOutsideBehavior bits-ui Interact outside behavior type. `close`: Closes the element immediately. `defer-otherwise-close`: Delegates the action to the parent element. If no parent is found, it closes the element. `defer-otherwise-ignore`: Delegates the action to the parent element. If no parent is found, nothing is done. `ignore`: Prevents the element from closing and also blocks the parent element from closing in response to an outside interaction. | InteractOutsideBehaviorType | undefined | `close` |
onCloseAutoFocus bits-ui Event handler called when auto-focusing on close. Can be prevented. | EventCallback | undefined | — |
onEscapeKeydown bits-ui Callback fired when escape is pressed. | ((e: KeyboardEvent) => void) | undefined | — |
onFocusOutside bits-ui Callback fired when focus leaves the dismissible layer. | ((event: FocusEvent) => void) | undefined | — |
onInteractOutside bits-ui Callback fired when an outside interaction event completes, which is either a `pointerup`, `mouseup`, or `touchend` event, depending on the user's input device. | InteractOutsideEventHandler | undefined | — |
onOpenAutoFocus bits-ui Event handler called when auto-focusing on open. Can be prevented. | EventCallback | undefined | — |
preventOverflowTextSelection bits-ui Passing `true` will prevent the overflow of text selection outside the element, provided the element is the top layer. | boolean | undefined | `true` |
preventScroll bits-ui Whether to prevent body scrolling when the content is open. | boolean | undefined | true |
ref bits-ui | HTMLElement | null | undefined | — |
restoreScrollDelay bits-ui The delay in milliseconds before the scrollbar is restored after closing the dialog. This is only applicable when using the `child` snippet for custom transitions and `preventScroll` is `true`. You should set this to a value greater than the transition duration to prevent content from shifting during the transition. | number | null | undefined | null |
trapFocus bits-ui Whether focus is trapped within the focus scope. | boolean | undefined | false |
AlertDialog.Title
| Prop | Type | Default |
|---|---|---|
class Extra classes merged onto the title. | string | — |
child bits-ui | Snippet<[{ props: Record<string, unknown>; }]> | undefined | — |
children bits-ui | Snippet<[]> | undefined | — |
id bits-ui | string | undefined | — |
level bits-ui The heading level of the dialog title. | 1 | 2 | 3 | 4 | 5 | 6 | undefined | — |
ref bits-ui | HTMLElement | null | undefined | — |
AlertDialog.Description
| Prop | Type | Default |
|---|---|---|
class Extra classes merged onto the description. | string | — |
child bits-ui | Snippet<[{ props: Record<string, unknown>; }]> | undefined | — |
children bits-ui | Snippet<[]> | undefined | — |
id bits-ui | string | undefined | — |
ref bits-ui | HTMLElement | null | undefined | — |
AlertDialog.Action
| Prop | Type | Default |
|---|---|---|
color Tone of the confirming button. `danger` is the default because an alert dialog usually guards a destructive action. | 'danger' | 'primary' | 'danger' |
class Extra classes merged onto the button. | string | — |
child bits-ui | Snippet<[{ props: Record<string, unknown>; }]> | undefined | — |
children bits-ui | Snippet<[]> | undefined | — |
id bits-ui | string | undefined | — |
ref bits-ui | HTMLElement | null | undefined | — |
AlertDialog.Cancel
| Prop | Type | Default |
|---|---|---|
class Extra classes merged onto the button. | string | — |
child bits-ui | Snippet<[{ props: Record<string, unknown>; }]> | undefined | — |
children bits-ui | Snippet<[]> | undefined | — |
id bits-ui | string | undefined | — |
ref bits-ui | HTMLElement | null | undefined | — |
AlertDialog.Root and Trigger are re-exported from
Bits unchanged, so their props are forwarded rather than redeclared.
AlertDialog.Content
AlertDialog.Action
Title, Description, Cancel and Overlay each take class plus their native attributes.