shadcn.io is an independent project built on shadcn/ui
Focus stays in a window over the page until the short task is done. Escape or Cancel puts it back on the button that opened the window.
Use it for a task with a start and a finish, like a profile edit or a share link. A destructive confirm that must not close on an outside click belongs in an Alert Dialog. In React, React Aria traps focus and restores it when the window closes.
Installation
Anatomy

DialogTrigger
DialogOverlay
DialogPositioner
DialogContent
DialogTitle
DialogDescription
DialogCloseUsage
import { Button } from "@/components/ui/button";
import {
Dialog, DialogClose, DialogDescription, DialogFooter, DialogHeader,
DialogTitle, DialogTrigger,
} from "@/components/ui/dialog";const DialogDemo = () => (
<DialogTrigger>
<form>
<Button variant="outline">Open Dialog</Button>
<Dialog className="sm:max-w-sm">
<DialogHeader>
<DialogTitle>Edit profile</DialogTitle>
<DialogDescription>
Make changes to your profile here. Click save when you're done.
</DialogDescription>
</DialogHeader>
<div className="flex flex-col gap-4">
<label className="flex flex-col gap-2 text-sm">
Name
<input
className="h-9 rounded-lg border border-input bg-transparent px-3"
defaultValue="Pedro Duarte"
name="name"
type="text"
/>
</label>
<label className="flex flex-col gap-2 text-sm">
Username
<input
className="h-9 rounded-lg border border-input bg-transparent px-3"
defaultValue="@peduarte"
name="username"
type="text"
/>
</label>
</div>
<DialogFooter>
<DialogClose variant="outline">Cancel</DialogClose>
<Button type="submit">Save changes</Button>
</DialogFooter>
</Dialog>
</form>
</DialogTrigger>
);Accessibility
- 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.
- EscEscape
- Closes the dialog and moves focus to trigger or the defined final focus element.
- Space
- Activate the focused control.
Demos
Close Button
A share dialog shows a read-only link and a Close button in the footer, wired with DialogClose. The corner icon is still there, and the labeled button is a second dismiss, aligned with the link. Use a labeled close when Close should read as an action, not only as an X. A plain footer button does not dismiss unless it is a DialogClose or you close the dialog yourself.
No Close Button
showCloseButton set to false removes the corner icon. This window has no other buttons, so Escape and an outside click are the way out. Hide the icon when it crowds a short title, not to force a choice. With Escape off too, a dialog that has no action is a trap, so a question people must answer belongs in an Alert Dialog with a real button.
Controlled
open lives in state. Save writes the name shown under the trigger, then closes, while Cancel still goes through DialogClose. Hold the open state when closing depends on a successful save, so a failed request can leave the window up with the error in it. Do not hang the save handler on DialogClose, because that dismisses before you know the request worked.
Sticky Footer
The paragraphs scroll inside a capped region, and the footer sits outside that scroller, so Close stays on screen. Use a sticky footer for terms, a long form, or any window where the action would otherwise scroll away. The header stays put for the same reason: it is not inside the scroller. Give that region a max height, or a dialog that grows with the page stops behaving like one.
Scrollable Content
The same scroll region, without a footer. The title and description stay visible while the paragraphs move. Use it for a note people read and then dismiss with the corner icon or Escape. If there is an action they must reach, pin it in a footer instead of leaving it under the prose, and keep a cap on the scroller so the window stays on screen.
Rtl
The content sets dir to rtl, and the copy is Arabic: title, fields, Cancel, and save. The close icon and the footer follow the inline end. Set dir on DialogContent when the window can be Arabic or Hebrew even if the trigger was drawn left to right. Do not shove the footer with a physical left margin, because logical alignment already moves the actions.
FAQ
Should I use a Dialog or an Alert Dialog?
Use a Dialog for a task: a form, a share link, a settings panel. When the only question is to confirm or cancel, like deleting a file, use an Alert Dialog, which doesn't close on an outside click. For content beside the page, a Sheet fits better.
How do I open and close a Dialog from code in React?
Hold the open state yourself, which also lets you close the dialog after an action, as in the Controlled demo.
Pass isOpen and update it in onOpenChange, which receives the new boolean.
How do I close a Dialog after a form is saved?
Control the open state, disable the submit button while the request runs, and set the state to closed once it succeeds, so the dialog stays open if the save fails. Don't put the save on DialogClose, which closes before the request finishes.
How do I stop a Dialog from closing on an outside click or Escape?
Set isDismissable to false for outside clicks and isKeyboardDismissDisabled for Escape.
Keep a visible way out, like a Cancel button.
How do I hide the close button in the corner of a Dialog?
Set showCloseButton to false on DialogContent, as in the No Close Button demo. It only hides the button: an outside click and Escape still close the dialog, so add your own close button or Cancel action in the footer.
Does a Dialog need a title for accessibility?
Yes. Every dialog needs a DialogTitle, which screen readers announce when it opens. When the design has no visible title, keep it and add the sr-only class. Focus moves into the dialog on open, stays inside while it's open, and goes back to the trigger when it closes.
How do I make a long Dialog scroll with a sticky footer?
Keep the header and footer outside the scrolling part and let the content between them scroll, as in the Sticky Footer and Scrollable Content demos.
How do I change the Dialog size or its layout on mobile?
Set size on DialogContent, from sm to 6xl or fullscreen. Sizes apply from the sm breakpoint up, so for a width of your own pass sm:max-w-* in className, as in shadcn/ui: it beats the size, where a bare max-w-* only applies below that breakpoint. On small screens the dialog sticks to the bottom of the screen like a sheet; set bottomStickOnMobile to false to keep it centered.
API Reference
Dialog
data-slot="dialog-content"
defaultOpen?boolean
Whether the overlay is open by default (uncontrolled).
- Default
false
onOpenChange?(isOpen: boolean) → void
Handler that is called when the overlay's open state changes.
- Parameters
isOpen– boolean- Returns
void
bottomStickOnMobile?boolean
Stick the dialog to the bottom of the screen on mobile.
- Default
true
isDismissable?boolean
Whether to close the modal when the user interacts outside it. Ark default: false.
- Default
true
isEntering?boolean
Whether the modal is currently performing an entry animation.
isExiting?boolean
Whether the modal is currently performing an exit animation.
isKeyboardDismissDisabled?boolean
Whether pressing the escape key to close the modal should be disabled.
- Default
false
isOpen?boolean
Whether the overlay is open by default (controlled).
onEnter?(element: HTMLElement) → void | Promise<void>
Callback when the modal starts entering. Return a promise to indicate when the entry animation has completed.
- Type
(element: HTMLElement) → void | Promise<void>- Parameters
element– HTMLElement- Returns
void | Promise<void>
onExit?(element: HTMLElement) → void | Promise<void>
Callback when the modal starts exiting. Return a promise to indicate when the exit animation has completed.
- Type
(element: HTMLElement) → void | Promise<void>- Parameters
element– HTMLElement- Returns
void | Promise<void>
role?"dialog" | "alertdialog"
The accessibility role for the dialog.
- Type
"dialog" | "alertdialog"- Default
"dialog"
shouldCloseOnInteractOutside?(element: Element) → boolean
When user interacts with the argument element outside of the overlay ref, return true if onClose should be called. This gives you a chance to filter out interaction with elements that should not dismiss the overlay. By default, onClose will always be called on interaction outside the overlay ref.
- Parameters
element– Element- Returns
boolean
showCloseButton?boolean
Show close button at the top right corner.
- Default
true
size?"2xl" | "3xl" | "4xl" | "5xl" | "6xl" | "fullscreen" | "lg" | "md" | "sm" | "xl"
The size.
- Type
"2xl" | "3xl" | "4xl" | "5xl" | "6xl" | "fullscreen" | "lg" | "md" | "sm" | "xl"- Default
"md"
slot?string | null
A slot name for the component. Slots allow the component to receive props from a parent
component. An explicit null value indicates that the local props completely override all
props received from a parent.
- Type
string | null
style?StyleOrFunction<T>
The inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element. A function may be provided to compute the style based on component state.
- Type
StyleOrFunction<T>
UNSTABLE_deferUntilEntered?boolean
Whether to wait until the entry animation completes before hiding content outside the modal and moving focus into it.
UNSTABLE_overrideFocus?boolean
Whether to override the focus() method so it does not scroll the page.
This is temporary and will be removed after fully testing all overlays.
UNSTABLE_portalContainer?Element
The container element in which the overlay portal will be placed. This may have unknown behavior depending on where it is portalled to. Deprecated. - Use a parent UNSAFE_PortalProvider to set your portal container instead.
- Default
document.body
render?DOMRenderFunction<E, T>
Overrides the default DOM element with a custom render function.
This allows rendering existing components with built-in styles and behaviors
such as router links, animation libraries, and pre-styled components.
Requirements:
- You must render the expected element type (e.g. if <button> is expected, you cannot render an
<a>).
- Only a single root DOM element can be rendered (no fragments).
- You must pass through props and ref to the underlying DOM element, merging with your own prop
as appropriate.
- Type
DOMRenderFunction<E, T>
className?string
Merged with the part's classes.
DialogTrigger
data-slot="dialog-trigger"
defaultOpen?boolean
Whether the overlay is open by default (uncontrolled).
onOpenChange?(isOpen: boolean) → void
Handler that is called when the overlay's open state changes.
- Parameters
isOpen– boolean- Returns
void
isOpen?boolean
Whether the overlay is open by default (controlled).
DialogClose
data-slot="dialog-close"
children?ReactNode
The content to display in the button.
clickEffect?boolean
Apply a click effect to the button.
- Default
true
download?LinkPrimitiveProps["download"]
With href, downloads the linked file instead of opening it.
href?string
When set, the button renders as a link.
isDisabled?boolean
Whether the button is disabled.
isLoading?boolean
Show a loading indicator.
- Default
false
rel?string
With href, the link's relationship to the page (noreferrer, …).
target?string
With href, where the linked page opens (_blank, …).
className?string
Merged with the part's classes.
DialogOverlay
data-slot="dialog-overlay"
defaultOpen?boolean
Whether the overlay is open by default (uncontrolled).
onOpenChange?(isOpen: boolean) → void
Handler that is called when the overlay's open state changes.
- Parameters
isOpen– boolean- Returns
void
children?ChildrenOrFunction<T>
The children of the component. A function may be provided to alter the children based on component state.
- Type
ChildrenOrFunction<T>
isDismissable?boolean
Whether to close the modal when the user interacts outside it.
- Default
false
isEntering?boolean
Whether the modal is currently performing an entry animation.
isExiting?boolean
Whether the modal is currently performing an exit animation.
isKeyboardDismissDisabled?boolean
Whether pressing the escape key to close the modal should be disabled.
- Default
false
isOpen?boolean
Whether the overlay is open by default (controlled).
onEnter?(element: HTMLElement) → void | Promise<void>
Callback when the modal starts entering. Return a promise to indicate when the entry animation has completed.
- Type
(element: HTMLElement) → void | Promise<void>- Parameters
element– HTMLElement- Returns
void | Promise<void>
onExit?(element: HTMLElement) → void | Promise<void>
Callback when the modal starts exiting. Return a promise to indicate when the exit animation has completed.
- Type
(element: HTMLElement) → void | Promise<void>- Parameters
element– HTMLElement- Returns
void | Promise<void>
shouldCloseOnInteractOutside?(element: Element) → boolean
When user interacts with the argument element outside of the overlay ref, return true if onClose should be called. This gives you a chance to filter out interaction with elements that should not dismiss the overlay. By default, onClose will always be called on interaction outside the overlay ref.
- Parameters
element– Element- Returns
boolean
slot?string | null
A slot name for the component. Slots allow the component to receive props from a parent
component. An explicit null value indicates that the local props completely override all
props received from a parent.
- Type
string | null
style?StyleOrFunction<T>
The inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element. A function may be provided to compute the style based on component state.
- Type
StyleOrFunction<T>
UNSTABLE_deferUntilEntered?boolean
Whether to wait until the entry animation completes before hiding content outside the modal and moving focus into it.
UNSTABLE_overrideFocus?boolean
Whether to override the focus() method so it does not scroll the page.
This is temporary and will be removed after fully testing all overlays.
UNSTABLE_portalContainer?Element
The container element in which the overlay portal will be placed. This may have unknown behavior depending on where it is portalled to. Deprecated. - Use a parent UNSAFE_PortalProvider to set your portal container instead.
- Default
document.body
render?DOMRenderFunction<E, T>
Overrides the default DOM element with a custom render function.
This allows rendering existing components with built-in styles and behaviors
such as router links, animation libraries, and pre-styled components.
Requirements:
- You must render the expected element type (e.g. if <button> is expected, you cannot render an
<a>).
- Only a single root DOM element can be rendered (no fragments).
- You must pass through props and ref to the underlying DOM element, merging with your own prop
as appropriate.
- Type
DOMRenderFunction<E, T>
className?string
Merged with the part's classes.
DialogHeader
<div> data-slot="dialog-header"
description?string
The description of the dialog.
title?string
The title of the dialog.
className?string
Merged with the part's classes.
DialogTitle
level?number
The heading level.
- Default
3
render?DOMRenderFunction<E, T>
Overrides the default DOM element with a custom render function.
This allows rendering existing components with built-in styles and behaviors
such as router links, animation libraries, and pre-styled components.
Requirements:
- You must render the expected element type (e.g. if <button> is expected, you cannot render an
<a>).
- Only a single root DOM element can be rendered (no fragments).
- You must pass through props and ref to the underlying DOM element, merging with your own prop
as appropriate.
- Type
DOMRenderFunction<E, T>
className?string
Merged with the part's classes.
DialogDescription
<div> data-slot="dialog-description"
className?string
Merged with the part's classes.
DialogFooter
<div> data-slot="dialog-footer"
showCloseButton?boolean
Show a close button in the footer.
- Default
false
className?string
Merged with the part's classes.











