Dialog
A modal window that appears on top of the main content.
Dialog Title
Anatomy
To use the dialog component correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-part
attribute to help identify them in the DOM.
Examples
Learn how to use the Dialog
component in your project. Let's take a look at the most basic example
import { Dialog, Portal } from '@ark-ui/react'
export const Basic = () => (
<Dialog.Root>
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Title>Dialog Title</Dialog.Title>
<Dialog.Description>Dialog Description</Dialog.Description>
<Dialog.CloseTrigger>Close</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
import { Portal } from 'solid-js/web'
import { Dialog } from '@ark-ui/solid'
export const Basic = () => {
return (
<Dialog.Root open>
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Title>Dialog Title</Dialog.Title>
<Dialog.Description>Dialog Description</Dialog.Description>
<Dialog.CloseTrigger>Close</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}
<script setup lang="ts">
import { Dialog } from '@ark-ui/vue'
</script>
<template>
<Dialog.Root>
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
<Teleport to="body">
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Title>Dialog Title</Dialog.Title>
<Dialog.Description>Dialog Description</Dialog.Description>
<Dialog.CloseTrigger>Close</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Teleport>
</Dialog.Root>
</template>
Controlled Dialog
To create a controlled Dialog component, manage the state of the dialog using the open
and
onOpenChange
props:
import { useState } from 'react'
import { Dialog, Portal } from '@ark-ui/react'
export const Controlled = () => {
const [isOpen, setIsOpen] = useState(false)
return (
<>
<button type="button" onClick={() => setIsOpen(true)}>
Open Dialog
</button>
<Dialog.Root open={isOpen} onOpenChange={(e) => setIsOpen(e.open)}>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Title>Dialog Title</Dialog.Title>
<Dialog.Description>Dialog Description</Dialog.Description>
<Dialog.CloseTrigger>Close</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
</>
)
}
import { createSignal } from 'solid-js'
import { Portal } from 'solid-js/web'
import { Dialog } from '@ark-ui/solid'
export const Controlled = () => {
const [isOpen, setIsOpen] = createSignal(false)
return (
<>
<button type="button" onClick={() => setIsOpen(true)}>
Open Dialog
</button>
<Dialog.Root open={isOpen()} onOpenChange={() => setIsOpen(false)}>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Title>Dialog Title</Dialog.Title>
<Dialog.Description>Dialog Description</Dialog.Description>
<Dialog.CloseTrigger>Close</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
</>
)
}
<script setup lang="ts">
import { ref } from 'vue'
import { Dialog } from '@ark-ui/vue'
const open = ref(false)
</script>
<template>
<button @click="() => (open = true)">Open Dialog</button>
<Dialog.Root v-model:open="open">
<Teleport to="body">
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Title>Dialog Title</Dialog.Title>
<Dialog.Description>Dialog Description</Dialog.Description>
<Dialog.CloseTrigger>Close</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Teleport>
</Dialog.Root>
</template>
Lazy Mounting
Lazy mounting is a feature that allows the content of a dialog to be rendered only when the dialog
is first opened. This is useful for performance optimization, especially when dialog content is
large or complex. To enable lazy mounting, use the lazyMount
prop on the Dialog.Root
component.
In addition, the unmountOnExit
prop can be used in conjunction with lazyMount
to unmount the
dialog content when the Dialog is closed, freeing up resources. The next time the dialog is
activated, its content will be re-rendered.
import { Dialog, Portal } from '@ark-ui/react'
export const LazyMount = () => (
<Dialog.Root lazyMount unmountOnExit onExitComplete={() => console.log('onExitComplete invoked')}>
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Title>Dialog Title</Dialog.Title>
<Dialog.Description>Dialog Description</Dialog.Description>
<Dialog.CloseTrigger>Close</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
import { Dialog } from '@ark-ui/solid'
export const LazyMount = () => {
return (
<Dialog.Root lazyMount unmountOnExit>
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Title>Dialog Title</Dialog.Title>
<Dialog.Description>Dialog Description</Dialog.Description>
<Dialog.CloseTrigger>Close</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Dialog.Root>
)
}
<script setup lang="ts">
import { Dialog } from '@ark-ui/vue'
</script>
<template>
<Dialog.Root lazyMount unmountOnExit>
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Title>Dialog Title</Dialog.Title>
<Dialog.Description>Dialog Description</Dialog.Description>
<Dialog.CloseTrigger>Close</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Dialog.Root>
</template>
Using Render Function
The Dialog component supports the use of a render function as a child for more control. This allows
access to dialog states like isOpen
:
import { Dialog, Portal } from '@ark-ui/react'
export const RenderFn = () => (
<Dialog.Root>
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Title>Dialog Title</Dialog.Title>
<Dialog.Description>Dialog Description</Dialog.Description>
<Dialog.CloseTrigger>Close</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
<Dialog.Context>
{(dialog) => <p>Dialog is {dialog.open ? 'open' : 'closed'}</p>}
</Dialog.Context>
</Dialog.Root>
)
import { Portal } from 'solid-js/web'
import { Dialog } from '@ark-ui/solid'
export const RenderFn = () => {
return (
<Dialog.Root>
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Title>Dialog Title</Dialog.Title>
<Dialog.Description>Dialog Description</Dialog.Description>
<Dialog.CloseTrigger>Close</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Portal>
<Dialog.Context>
{(context) => <p>Dialog is {context().open ? 'open' : 'closed'}</p>}
</Dialog.Context>
</Dialog.Root>
)
}
<script setup lang="ts">
import { Dialog } from '@ark-ui/vue'
</script>
<template>
<Dialog.Root>
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
<Teleport to="body">
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.Title>Dialog Title</Dialog.Title>
<Dialog.Description>Dialog Description</Dialog.Description>
<Dialog.CloseTrigger>Close</Dialog.CloseTrigger>
</Dialog.Content>
</Dialog.Positioner>
</Teleport>
<Dialog.Context v-slot="dialog">
<p>Dialog is {{ dialog.open ? 'open' : 'closed' }}</p>
</Dialog.Context>
</Dialog.Root>
</template>
API Reference
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 |