Components
Dialog

Dialog

A modal window that appears on top of the main content.

Loading...

You can explore the dialog component in the following curated examples.

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 Escape
  • closeOnInteractOutside={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

PropDefaultType
aria-label
string

Human readable label for the dialog, in event the dialog title is not rendered

closeOnEscapetrue
boolean

Whether to close the dialog when the escape key is pressed

closeOnInteractOutsidetrue
boolean

Whether to close the dialog when the outside is clicked

defaultOpenfalse
boolean

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

Element to receive focus when the dialog is closed

id
string

The 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
boolean

Whether to synchronize the present change immediately or defer it to the next frame

initialFocusEl
() => MaybeElement

Element to receive focus when the dialog is opened

lazyMountfalse
boolean

Whether to enable lazy mounting

modaltrue
boolean

Whether to prevent pointer interaction outside the element and hide all content below it

onEscapeKeyDown
(event: KeyboardEvent) => void

Function called when the escape key is pressed

onExitComplete
VoidFunction

Function called when the animation ends in the closed state

onFocusOutside
(event: FocusOutsideEvent) => void

Function called when the focus is moved outside the component

onInteractOutside
(event: InteractOutsideEvent) => void

Function called when an interaction happens outside the component

onOpenChange
(details: OpenChangeDetails) => void

Function to call when the dialog's open state changes

onPointerDownOutside
(event: PointerDownOutsideEvent) => void

Function called when the pointer is pressed down outside the component

onRequestDismiss
(event: LayerDismissEvent) => void

Function called when this layer is closed due to a parent layer being closed

open
boolean

The 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
boolean

Whether the node is present (controlled by the user)

preventScrolltrue
boolean

Whether to prevent scrolling behind the dialog when it's opened

restoreFocus
boolean

Whether to restore focus to the element that had focus before the dialog was opened

role'dialog'
'dialog' | 'alertdialog'

The dialog's role

skipAnimationOnMountfalse
boolean

Whether to allow the initial presence animation.

trapFocustrue
boolean

Whether to trap focus inside the dialog when it's opened

unmountOnExitfalse
boolean

Whether to unmount on exit.

Backdrop

Renders a <div> element.

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
AttributeDescription
[data-scope]dialog
[data-part]backdrop
[data-state]"open" | "closed"
CSS VariableDescription
--layer-indexThe index of the dismissable in the layer stack

CloseTrigger

Renders a <button> element.

PropDefaultType
asChild
boolean

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

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
AttributeDescription
[data-scope]dialog
[data-part]content
[data-state]"open" | "closed"
[data-nested]dialog
[data-has-nested]dialog
CSS VariableDescription
--layer-indexThe index of the dismissable in the layer stack
--nested-layer-countThe number of nested dialogs

Description

Renders a <div> element.

PropDefaultType
asChild
boolean

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

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

RootProvider

PropDefaultType
value
UseDialogReturn

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
immediate
boolean

Whether to synchronize the present change immediately or defer it to the next frame

lazyMountfalse
boolean

Whether to enable lazy mounting

onExitComplete
VoidFunction

Function called when the animation ends in the closed state

present
boolean

Whether the node is present (controlled by the user)

skipAnimationOnMountfalse
boolean

Whether to allow the initial presence animation.

unmountOnExitfalse
boolean

Whether to unmount on exit.

Title

Renders a <h2> element.

PropDefaultType
asChild
boolean

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

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
AttributeDescription
[data-scope]dialog
[data-part]trigger
[data-state]"open" | "closed"

Context

API

PropertyType
open
boolean

Whether the dialog is open

setOpen
(open: boolean) => void

Function to open or close the dialog

Accessibility

Complies with the Dialog WAI-ARIA design pattern.

Keyboard Support

KeyDescription
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