import { Button } from "@chakra-ui/react"
import {
DialogActionTrigger,
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
const Demo = () => {
return (
<DialogRoot>
<DialogTrigger asChild>
<Button variant="outline" size="sm">
Open Dialog
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
</DialogHeader>
<DialogBody>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</DialogBody>
<DialogFooter>
<DialogActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</DialogActionTrigger>
<Button>Save</Button>
</DialogFooter>
<DialogCloseTrigger />
</DialogContent>
</DialogRoot>
)
}
Setup
If you don't already have the snippet, run the following command to add the
dialog snippet
npx @chakra-ui/cli snippet add dialog
The snippet includes a closed component composition for the Dialog component.
Usage
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
<DialogRoot>
<DialogBackdrop />
<DialogTrigger />
<DialogContent>
<DialogCloseTrigger />
<DialogHeader>
<DialogTitle />
</DialogHeader>
<DialogBody />
<DialogFooter />
</DialogContent>
</DialogRoot>
Examples
Sizes
Use the size prop to change the size of the dialog component.
import { Button, For, HStack } from "@chakra-ui/react"
import {
DialogActionTrigger,
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
const Demo = () => {
return (
<HStack>
<For each={["xs", "sm", "md", "lg"]}>
{(size) => (
<DialogRoot key={size} size={size}>
<DialogTrigger asChild>
<Button variant="outline" size={size}>
Open ({size})
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
</DialogHeader>
<DialogBody>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</DialogBody>
<DialogFooter>
<DialogActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</DialogActionTrigger>
<Button>Save</Button>
</DialogFooter>
<DialogCloseTrigger />
</DialogContent>
</DialogRoot>
)}
</For>
</HStack>
)
}
Cover
Use the size="cover" prop to make the dialog component cover the entire screen
while revealing a small portion of the page behind.
import { Button } from "@chakra-ui/react"
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
const Demo = () => {
return (
<DialogRoot size="cover" placement="center" motionPreset="slide-in-bottom">
<DialogTrigger asChild>
<Button variant="outline" size="sm">
Open Dialog
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
<DialogCloseTrigger />
</DialogHeader>
<DialogBody>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</DialogBody>
</DialogContent>
</DialogRoot>
)
}
Fullscreen
Use the size="full" prop to make the dialog component take up the entire
screen.
import { Button } from "@chakra-ui/react"
import {
DialogActionTrigger,
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
const Demo = () => {
return (
<DialogRoot size="full" motionPreset="slide-in-bottom">
<DialogTrigger asChild>
<Button variant="outline" size="sm">
Open Dialog
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
</DialogHeader>
<DialogBody>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</DialogBody>
<DialogFooter>
<DialogActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</DialogActionTrigger>
<Button>Save</Button>
</DialogFooter>
<DialogCloseTrigger />
</DialogContent>
</DialogRoot>
)
}
Placement
Use the placement prop to change the placement of the dialog component.
import { Button, For, HStack } from "@chakra-ui/react"
import {
DialogActionTrigger,
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
const Demo = () => {
return (
<HStack wrap="wrap" gap="4">
<For each={["top", "center", "bottom"]}>
{(placement) => (
<DialogRoot
key={placement}
placement={placement}
motionPreset="slide-in-bottom"
>
<DialogTrigger asChild>
<Button variant="outline">Open Dialog ({placement}) </Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
</DialogHeader>
<DialogBody>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</DialogBody>
<DialogFooter>
<DialogActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</DialogActionTrigger>
<Button>Save</Button>
</DialogFooter>
<DialogCloseTrigger />
</DialogContent>
</DialogRoot>
)}
</For>
</HStack>
)
}
Controlled
Use the open and onOpenChange prop to control the visibility of the dialog
component.
"use client"
import { Button } from "@chakra-ui/react"
import {
DialogActionTrigger,
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { useState } from "react"
import Lorem from "react-lorem-ipsum"
const Demo = () => {
const [open, setOpen] = useState(false)
return (
<DialogRoot lazyMount open={open} onOpenChange={(e) => setOpen(e.open)}>
<DialogTrigger asChild>
<Button variant="outline">Open</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
</DialogHeader>
<DialogBody>
<Lorem p={2} />
</DialogBody>
<DialogFooter>
<DialogActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</DialogActionTrigger>
<Button>Save</Button>
</DialogFooter>
<DialogCloseTrigger />
</DialogContent>
</DialogRoot>
)
}
Store
An alternative way to control the dialog is to use the RootProvider component
and the useDialog store hook.
This way you can access the dialog state and methods from outside the dialog.
"use client"
import { Button, DialogRootProvider, useDialog } from "@chakra-ui/react"
import {
DialogActionTrigger,
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
const Demo = () => {
const dialog = useDialog()
return (
<DialogRootProvider value={dialog}>
<DialogTrigger asChild>
<Button variant="outline" size="sm">
{dialog.open ? "Close" : "Open"} Dialog
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
</DialogHeader>
<DialogBody>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</DialogBody>
<DialogFooter>
<DialogActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</DialogActionTrigger>
<Button>Save</Button>
</DialogFooter>
<DialogCloseTrigger />
</DialogContent>
</DialogRootProvider>
)
}
Context
Use the DialogContext component to access the dialog state and methods from
outside the dialog.
"use client"
import { Button, DialogContext } from "@chakra-ui/react"
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogRoot,
DialogTrigger,
} from "@/components/ui/dialog"
const Demo = () => {
return (
<DialogRoot>
<DialogTrigger asChild>
<Button variant="outline" size="sm">
Open Dialog
</Button>
</DialogTrigger>
<DialogContent>
<DialogContext>
{(store) => (
<>
<DialogBody>
<p>Dialog is open: {store.open ? "true" : "false"}</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
<button onClick={() => store.setOpen(false)}>Close</button>
</DialogBody>
</>
)}
</DialogContext>
<DialogCloseTrigger />
</DialogContent>
</DialogRoot>
)
}
Initial Focus
Use the initialFocusEl prop to set the initial focus of the dialog component.
"use client"
import { Button, Input, Stack } from "@chakra-ui/react"
import {
DialogActionTrigger,
DialogBody,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Field } from "@/components/ui/field"
import { useRef } from "react"
const Demo = () => {
const ref = useRef<HTMLInputElement>(null)
return (
<DialogRoot initialFocusEl={() => ref.current}>
<DialogTrigger asChild>
<Button variant="outline">Open</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Dialog Header</DialogTitle>
</DialogHeader>
<DialogBody pb="4">
<Stack gap="4">
<Field label="First Name">
<Input placeholder="First Name" />
</Field>
<Field label="Last Name">
<Input ref={ref} placeholder="Focus First" />
</Field>
</Stack>
</DialogBody>
<DialogFooter>
<DialogActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</DialogActionTrigger>
<Button>Save</Button>
</DialogFooter>
</DialogContent>
</DialogRoot>
)
}
Inside Scroll
Use the scrollBehavior=inside prop to change the scroll behavior of the dialog
when its content overflows.
import { Button } from "@chakra-ui/react"
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import Lorem from "react-lorem-ipsum"
const Demo = () => {
return (
<DialogRoot scrollBehavior="inside" size="sm">
<DialogTrigger asChild>
<Button variant="outline">Inside Scroll</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>With Inside Scroll</DialogTitle>
</DialogHeader>
<DialogCloseTrigger />
<DialogBody>
<Lorem p={8} />
</DialogBody>
</DialogContent>
</DialogRoot>
)
}
Outside Scroll
Use the scrollBehavior=outside prop to change the scroll behavior of the
dialog when its content overflows.
import { Button } from "@chakra-ui/react"
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import Lorem from "react-lorem-ipsum"
const Demo = () => {
return (
<DialogRoot size="sm" scrollBehavior="outside">
<DialogTrigger asChild>
<Button variant="outline">Outside Scroll</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>With Outside Scroll</DialogTitle>
</DialogHeader>
<DialogCloseTrigger />
<DialogBody>
<Lorem p={8} />
</DialogBody>
</DialogContent>
</DialogRoot>
)
}
Motion Preset
Use the motionPreset prop to change the animation of the dialog component.
import { Button } from "@chakra-ui/react"
import {
DialogActionTrigger,
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
const Demo = () => {
return (
<DialogRoot motionPreset="slide-in-bottom">
<DialogTrigger asChild>
<Button variant="outline">Slide in Bottom</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
</DialogHeader>
<DialogBody>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</DialogBody>
<DialogFooter>
<DialogActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</DialogActionTrigger>
<Button>Save</Button>
</DialogFooter>
<DialogCloseTrigger />
</DialogContent>
</DialogRoot>
)
}
Alert Dialog
Set the role: "alertdialog" prop to change the dialog component to an alert
dialog.
import { Button } from "@chakra-ui/react"
import {
DialogActionTrigger,
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
const Demo = () => {
return (
<DialogRoot role="alertdialog">
<DialogTrigger asChild>
<Button variant="outline" size="sm">
Open Dialog
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure?</DialogTitle>
</DialogHeader>
<DialogBody>
<p>
This action cannot be undone. This will permanently delete your
account and remove your data from our systems.
</p>
</DialogBody>
<DialogFooter>
<DialogActionTrigger asChild>
<Button variant="outline">Cancel</Button>
</DialogActionTrigger>
<Button colorPalette="red">Delete</Button>
</DialogFooter>
<DialogCloseTrigger />
</DialogContent>
</DialogRoot>
)
}
Close Button Outside
Here's an example of how to customize the DialogCloseTrigger component to
position the close button outside the dialog component.
import { AspectRatio, Button } from "@chakra-ui/react"
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogDescription,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
const Demo = () => {
return (
<DialogRoot placement="center">
<DialogTrigger asChild>
<Button variant="outline" size="sm">
Open Dialog
</Button>
</DialogTrigger>
<DialogContent>
<DialogBody pt="4">
<DialogTitle>Dialog Title</DialogTitle>
<DialogDescription mb="4">
This is a dialog with some content and a video.
</DialogDescription>
<AspectRatio ratio={4 / 3} rounded="lg" overflow="hidden">
<iframe
title="naruto"
src="https://www.youtube.com/embed/QhBnZ6NPOY0"
allowFullScreen
/>
</AspectRatio>
</DialogBody>
<DialogCloseTrigger top="0" insetEnd="-12" bg="bg" />
</DialogContent>
</DialogRoot>
)
}
With DataList
Here's an example of how to compose the dialog component with the DataList
component.
import { Badge, Button, HStack, Textarea, VStack } from "@chakra-ui/react"
import { Avatar } from "@/components/ui/avatar"
import { DataListItem, DataListRoot } from "@/components/ui/data-list"
import {
DialogBody,
DialogCloseTrigger,
DialogContent,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
const Demo = () => {
return (
<VStack alignItems="start">
<DialogRoot>
<DialogTrigger asChild>
<Button variant="outline">Open Dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Prepare Chakra V3</DialogTitle>
</DialogHeader>
<DialogBody pb="8">
<DataListRoot orientation="horizontal">
<DataListItem
label="Status"
value={<Badge colorPalette="green">Completed</Badge>}
/>
<DataListItem
label="Assigned to"
value={
<HStack>
<Avatar
size="xs"
name="Segun Adebayo"
src="https://bit.ly/sage-adebayo"
/>
Segun Adebayo
</HStack>
}
/>
<DataListItem label="Due date" value="12th August 2024" />
</DataListRoot>
<Textarea placeholder="Add a note" mt="8" />
</DialogBody>
<DialogCloseTrigger />
</DialogContent>
</DialogRoot>
</VStack>
)
}
Props
Root
| Prop | Default | Type |
|---|---|---|
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 |
lazyMount | false | booleanWhether to enable lazy mounting |
modal | true | booleanWhether to prevent pointer interaction outside the element and hide all content below it |
preventScroll | true | booleanWhether to prevent scrolling behind the dialog when it's opened |
role | '\'dialog\'' | 'dialog' | 'alertdialog'The dialog's role |
trapFocus | true | booleanWhether to trap focus inside the dialog when it's opened |
unmountOnExit | false | booleanWhether to unmount on exit. |
colorPalette | 'gray' | 'gray' | 'red' | 'orange' | 'yellow' | 'green' | 'teal' | 'blue' | 'cyan' | 'purple' | 'pink' | 'accent'The color palette of the component |
scrollBehavior | 'outside' | 'inside' | 'outside'The scrollBehavior of the component |
size | 'md' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full'The size of the component |
motionPreset | 'scale' | 'scale' | 'slide-in-bottom' | 'slide-in-top' | 'slide-in-left' | 'slide-in-right' | 'none'The motionPreset of the component |
aria-label | stringHuman readable label for the dialog, in event the dialog title is not rendered | |
defaultOpen | booleanThe initial open state of the dialog when it is first rendered. Use when you do not need to control its open state. | |
finalFocusEl | () => HTMLElement | nullElement 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 | () => HTMLElement | nullElement to receive focus when the dialog is opened | |
onEscapeKeyDown | (event: KeyboardEvent) => voidFunction called when the escape key is pressed | |
onExitComplete | () => voidFunction 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) => voidCallback to be invoked when the dialog is opened or closed | |
onPointerDownOutside | (event: PointerDownOutsideEvent) => voidFunction called when the pointer is pressed down outside the component | |
open | booleanWhether the dialog is open | |
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) | |
restoreFocus | booleanWhether to restore focus to the element that had focus before the dialog was opened | |
centered | 'true' | 'false'The centered of the component | |
as | React.ElementTypeThe underlying element to render. | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
unstyled | booleanWhether to remove the component's style. |