Dialog
A modal window that appears on top of the main content.
You can explore the dialog component in the following curated examples.
Command Menu
Render a Command Palette that opens when CMD + K is pressed.
Dialog with Tooltip
Render a Dialog with a Tooltip that shows upon hovering over the Dialog Trigger.
Anatomy
<Dialog.Root>
<Dialog.Trigger />
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Title />
<Dialog.Description />
<Dialog.CloseTrigger />
</Dialog.Content>
</Dialog.Positioner>
</Dialog.Root>
Examples
Controlled
Manage the dialog state using the open and onOpenChange props.
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.
Alert Dialog
For critical confirmations or destructive actions, use role="alertdialog". Alert dialogs differ from regular dialogs
in important ways:
- Automatic focus: The close/cancel button receives focus when opened, prioritizing the safest action
- Requires explicit dismissal: Cannot be closed by clicking outside, only via button clicks or Escape key
Lazy Mount
Use lazyMount to render dialog content only when first opened. Combine with unmountOnExit to unmount when closed,
freeing up resources.
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.
Non-Modal
Use modal={false} to allow interaction with elements outside the dialog. Disables focus trapping and scroll
prevention.
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.
Context
Use the Dialog.Context component to access the dialog's state and methods.
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.
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().
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 React.lazy or Next.js dynamic, wrap the imported component in Suspense:
import { Dialog } from '@ark-ui/react/dialog'
import { Suspense } from 'react'
import dynamic from 'next/dynamic'
const HeavyComponent = dynamic(() => import('./HeavyComponent'))
export const Demo = () => (
<Dialog.Root lazyMount>
<Dialog.Trigger>Open</Dialog.Trigger>
<Dialog.Content>
<Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</Suspense>
</Dialog.Content>
</Dialog.Root>
)
API Reference
Props
Root
| Prop | Default | Type |
|---|---|---|
aria-label | stringHuman readable label for the dialog, in event the dialog title is not rendered | |
closeOnEscape | true | booleanWhether to close the dialog when the escape key is pressed |
closeOnInteractOutside | true | booleanWhether to close the dialog when the outside is clicked |
defaultOpen | false | booleanThe initial open state of the dialog when rendered. Use when you don't need to control the open state of the dialog. |
finalFocusEl | () => MaybeElementElement to receive focus when the dialog is closed | |
id | stringThe unique identifier of the machine. | |
ids | Partial<{
trigger: string
positioner: string
backdrop: string
content: string
closeTrigger: string
title: string
description: string
}>The ids of the elements in the dialog. Useful for composition. | |
immediate | booleanWhether to synchronize the present change immediately or defer it to the next frame | |
initialFocusEl | () => MaybeElementElement to receive focus when the dialog is opened | |
lazyMount | false | booleanWhether to enable lazy mounting |
modal | true | booleanWhether to prevent pointer interaction outside the element and hide all content below it |
onEscapeKeyDown | (event: KeyboardEvent) => voidFunction called when the escape key is pressed | |
onExitComplete | VoidFunctionFunction called when the animation ends in the closed state | |
onFocusOutside | (event: FocusOutsideEvent) => voidFunction called when the focus is moved outside the component | |
onInteractOutside | (event: InteractOutsideEvent) => voidFunction called when an interaction happens outside the component | |
onOpenChange | (details: OpenChangeDetails) => voidFunction to call when the dialog's open state changes | |
onPointerDownOutside | (event: PointerDownOutsideEvent) => voidFunction called when the pointer is pressed down outside the component | |
onRequestDismiss | (event: LayerDismissEvent) => voidFunction called when this layer is closed due to a parent layer being closed | |
open | booleanThe controlled open state of the dialog | |
persistentElements | (() => Element | null)[]Returns the persistent elements that: - should not have pointer-events disabled - should not trigger the dismiss event | |
present | booleanWhether the node is present (controlled by the user) | |
preventScroll | true | booleanWhether to prevent scrolling behind the dialog when it's opened |
restoreFocus | booleanWhether to restore focus to the element that had focus before the dialog was opened | |
role | 'dialog' | 'dialog' | 'alertdialog'The dialog's role |
skipAnimationOnMount | false | booleanWhether to allow the initial presence animation. |
trapFocus | true | booleanWhether to trap focus inside the dialog when it's opened |
unmountOnExit | false | booleanWhether to unmount on exit. |
Backdrop
Renders a <div> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Attribute | Description |
|---|---|
[data-scope] | dialog |
[data-part] | backdrop |
[data-state] | "open" | "closed" |
| CSS Variable | Description |
|---|---|
--layer-index | The index of the dismissable in the layer stack |
CloseTrigger
Renders a <button> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Content
Renders a <div> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Attribute | Description |
|---|---|
[data-scope] | dialog |
[data-part] | content |
[data-state] | "open" | "closed" |
[data-nested] | dialog |
[data-has-nested] | dialog |
| CSS Variable | Description |
|---|---|
--layer-index | The index of the dismissable in the layer stack |
--nested-layer-count | The number of nested dialogs |
Description
Renders a <div> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Positioner
Renders a <div> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
RootProvider
| Prop | Default | Type |
|---|---|---|
value | UseDialogReturn | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
immediate | booleanWhether to synchronize the present change immediately or defer it to the next frame | |
lazyMount | false | booleanWhether to enable lazy mounting |
onExitComplete | VoidFunctionFunction called when the animation ends in the closed state | |
present | booleanWhether the node is present (controlled by the user) | |
skipAnimationOnMount | false | booleanWhether to allow the initial presence animation. |
unmountOnExit | false | booleanWhether to unmount on exit. |
Title
Renders a <h2> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Trigger
Renders a <button> element.
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Attribute | Description |
|---|---|
[data-scope] | dialog |
[data-part] | trigger |
[data-state] | "open" | "closed" |
Context
API
| Property | Type |
|---|---|
open | booleanWhether the dialog is open |
setOpen | (open: boolean) => voidFunction to open or close the dialog |
Accessibility
Complies with the Dialog WAI-ARIA design pattern.
Keyboard Support
| Key | Description |
|---|---|
Enter | When focus is on the trigger, opens the dialog. |
Tab | Moves focus to the next focusable element within the content. Focus is trapped within the dialog. |
Shift + Tab | Moves focus to the previous focusable element. Focus is trapped within the dialog. |
Esc | Closes the dialog and moves focus to trigger or the defined final focus element |