Import
import {
Dialog,
DialogTrigger,
DialogHeading,
DialogDescription,
DialogCloseTrigger,
DialogCloseIconTrigger,
} from '@cerberus-design/react'Usage
To use the Dialog component, wrap it in a DialogProvider and use the DialogTrigger component to open the dialog. The Dialog component is a controlled component that can be used to display content in a modal.
Sizes
The Dialog component supports different sizes. You can set the size prop to xs to lg, or full.
Controlled
Manage the dialog state using the open and onOpenChange props.
Note
Notice how the dialog triggers automagically handle the state management via onOpenChange.
Root Provider
An alternative way to control the dialog is to use the RootProvider component and the useDialog hook. This way you can access the state and methods from outside the component.
Lazy Mount
Use lazyMount to render dialog content only when first opened. Combine with unmountOnExit to unmount when closed, freeing up resources.
Prefer this over conditionally rendering DialogProvider — see Conditional Rendering.
Inside Scroll
Make the content area scrollable while keeping header and footer fixed using maxHeight and overflow: auto.
Outside Scroll
Make the positioner scrollable so the dialog can extend beyond the viewport.
Initial Focus
Use initialFocusEl to control which element receives focus when the dialog opens.
Final Focus
Use finalFocusEl to control which element receives focus when the dialog closes. Defaults to the trigger element.
Context
Access the dialog's state and methods with DialogContext or the useDialogContext hook.
Open from Menu
Open a dialog imperatively from a Menu item using the onClick handler.
Nested
Nest dialogs within one another. The parent receives data-has-nested and --nested-layer-count CSS variable for styling effects like zoom-out:
[data-part='content'][data-has-nested] {
transform: scale(calc(1 - var(--nested-layer-count) * 0.05));
}Confirmation
Intercept close attempts to show confirmation prompts, preventing data loss from unsaved changes.
Non-Modal
We don't recommend using a non-modal dialog due to the accessibility concerns they present. In event you need it, here's what you can do:
- set the
modalprop tofalse - set
pointerEventstononeon theDialog.Positionercomponent - (optional) set the
closeOnInteractOutsideprop tofalsePreview
Guides
Close Behavior
closeOnEscape={false}- Prevent closing on EscapecloseOnInteractOutside={false}- Prevent closing on outside click
For conditional control, use onEscapeKeyDown or onInteractOutside with e.preventDefault().
Conditional Rendering
Unmounting Dialog.Root when toggling open state can break focus, scroll lock, and cleanup. Keep the root mounted and control it with open / onOpenChange.
When you want portal content out of the DOM while closed, add lazyMount and unmountOnExit to the root.
Z-index Stacking
Use the --layer-index CSS variable for z-index management of stacked dialogs:
[data-part='content'] {
z-index: calc(var(--layer-index));
}Dynamic Imports
When using lazyMount with lazy or Next.js dynamic, wrap the imported component in Suspense:
Customizing
You can customize the Dialog using style props and data selectors on any slot primitve.
Primitives
You can utilize the primitive components or the css prop to customize the dialog.
| Component | Description |
|---|---|
DialogProvider | The main state context for the dialog. |
DialogTrigger | The trigger element that opens the dialog. |
DialogBackdrop | The backdrop that covers the page when the dialog is open. |
DialogPositioner | The container that positions the dialog content. |
DialogContent | The content that is shown within the dialog. |
DialogHeading | The heading title of the dialog. |
DialogDescription | The description of the dialog. |
DialogCloseTrigger | The trigger element that closes the dialog. |
DialogCloseIconTrigger | The trigger element that closes the dialog with an "x" icon. |
API
Props
The Dialog component is an abstraction of the primitives and accepts the following props:
Root Props:
| Prop | Type | Required | Description |
|---|---|---|---|
aria-label | string | No | Human readable label for the dialog, in event the dialog title is not rendered |
closeOnEscape | boolean | No | Whether to close the dialog when the escape key is pressed |
closeOnInteractOutside | boolean | No | Whether to close the dialog when the outside is clicked |
defaultOpen | boolean | No | The initial open state of the dialog when rendered. Use when you don't need to control the open state of the dialog. |
finalFocusEl | () => MaybeElement | No | Element to receive focus when the dialog is closed |
id | string | No | The unique identifier of the machine. |
ids | Partial<PrimitiveLayers> | No | The ids of the elements in the dialog. Useful for composition. |
immediate | boolean | No | Whether to synchronize the present change immediately or defer it to the next frame |
initialFocusEl | () => MaybeElement | No | Element to receive focus when the dialog is opened |
lazyMount | boolean | No | Whether to enable lazy mounting |
modal | boolean | No | Whether to prevent pointer interaction outside the element and hide all content below it |
onEscapeKeyDown | (event: KeyboardEvent) => void | No | Function called when the escape key is pressed |
onExitComplete | VoidFunction | No | Function called when the animation ends in the closed state |
onFocusOutside | (event: FocusOutsideEvent) => void | No | Function called when the focus is moved outside the component |
onInteractOutside | (event: InteractOutsideEvent) => void | No | Function called when an interaction happens outside the component |
onOpenChange | (details: OpenChangeDetails) => void | No | Function to call when the dialog's open state changes |
onPointerDownOutside | (event: PointerDownOutsideEvent) => void | No | Function called when the pointer is pressed down outside the component |
onRequestDismiss | (event: LayerDismissEvent) => void | No | Function called when this layer is closed due to a parent layer being closed |
open | boolean | No | The controlled open state of the dialog |
persistentElements | (() => Element | null)[] | No | Returns the persistent elements that: should not have pointer-events disabled or should not trigger the dismiss event |
present | boolean | No | Whether the node is present (controlled by the user) |
preventScroll | boolean | No | Whether to prevent scrolling behind the dialog when it's opened |
restoreFocus | boolean | No | Whether to restore focus to the element that had focus before the dialog was opened |
role | 'dialog' | 'alertdialog' | No | The dialog's role |
skipAnimationOnMount | boolean | No | Whether to allow the initial presence animation. |
size | string | No | This size of the Dialog. |
trapFocus | boolean | No | Whether to trap focus inside the dialog when it's opened |
unmountOnExit | boolean | No | Whether to unmount on exit. |
Backdrop Props:
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
Backdrop Data Attributes:
| Attribute | Value |
|---|---|
[data-scope] | dialog |
[data-part] | backdrop |
[data-state] | "open" | "closed" |
Backdrop CSS Variables:
| Variable | Description |
|---|---|
--layer-index | The index of the dismissable in the layer stack |
CloseTrigger Props:
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
Content Props:
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
Content Data Attributes:
| Attribute | Value |
|---|---|
[data-scope] | dialog |
[data-part] | content |
[data-state] | "open" | "closed" |
[data-nested] | dialog |
[data-has-nested] | dialog |
Content CSS Variables:
| Variable | Description |
|---|---|
--layer-index | The index of the dismissable in the layer stack |
--nested-layer-count | The number of nested dialogs |
Description Props:
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
Positioner Props:
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
RootProvider Props
| Prop | Type | Required | Description |
|---|---|---|---|
value | UseDialogReturn | Yes | |
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
immediate | boolean | No | Whether to synchronize the present change immediately or defer it to the next frame |
lazyMount | boolean | No | Whether to enable lazy mounting |
onExitComplete | VoidFunction | No | Function called when the animation ends in the closed state |
present | boolean | No | Whether the node is present (controlled by the user) |
skipAnimationOnMount | boolean | No | Whether to allow the initial presence animation. |
unmountOnExit | boolean | No | Whether to unmount on exit. |
Title Props:
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
Trigger Props
| Prop | Type | Required | Description |
|---|---|---|---|
asChild | boolean | No | Use the provided child element as the default rendered element, combining their props and behavior. |
Trigger Data Attributes
| Attribute | Value |
|---|---|
[data-scope] | dialog |
[data-part] | trigger |
[data-value] | The value of the item |
[data-state] | "open" | "closed" |
[data-current] | Present when current |