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 | boolean Whether to close the dialog when the escape key is pressed |
closeOnInteractOutside | true | boolean Whether to close the dialog when the outside is clicked |
lazyMount | false | boolean Whether to enable lazy mounting |
modal | true | boolean Whether to prevent pointer interaction outside the element and hide all content below it |
preventScroll | true | boolean Whether to prevent scrolling behind the dialog when it's opened |
role | '\'dialog\'' | 'dialog' | 'alertdialog' The dialog's role |
trapFocus | true | boolean Whether to trap focus inside the dialog when it's opened |
unmountOnExit | false | boolean Whether 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 | string Human readable label for the dialog, in event the dialog title is not rendered | |
defaultOpen | boolean The initial open state of the dialog when it is first rendered. Use when you do not need to control its open state. | |
finalFocusEl | () => HTMLElement | null 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 | () => HTMLElement | null Element to receive focus when the dialog is opened | |
onEscapeKeyDown | (event: KeyboardEvent) => void Function called when the escape key is pressed | |
onExitComplete | () => void 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 Callback to be invoked when the dialog is opened or closed | |
onPointerDownOutside | (event: PointerDownOutsideEvent) => void Function called when the pointer is pressed down outside the component | |
open | boolean Whether 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 | boolean Whether the node is present (controlled by the user) | |
restoreFocus | boolean Whether to restore focus to the element that had focus before the dialog was opened | |
centered | 'true' | 'false' The centered of the component | |
as | React.ElementType The underlying element to render. | |
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
unstyled | boolean Whether to remove the component's style. |