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 onInteractOutside on 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

PropTypeDefault
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

PropTypeDefault
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 | undefinedtrue
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 | undefinednull
trapFocus bits-ui Whether focus is trapped within the focus scope.boolean | undefinedfalse

AlertDialog.Title

PropTypeDefault
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

PropTypeDefault
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

PropTypeDefault
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

PropTypeDefault
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.