---
import { Button } from "@/components/ui/button"
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Field, FieldGroup } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
---
<Dialog>
<form>
<DialogTrigger variant="outline">Open Dialog</DialogTrigger>
<DialogContent class="sm:max-w-sm">
<DialogHeader>
<DialogTitle>Edit profile</DialogTitle>
<DialogDescription>
Make changes to your profile here. Click save when you're done.
</DialogDescription>
</DialogHeader>
<FieldGroup>
<Field>
<Label for="name-1">Name</Label>
<Input id="name-1" name="name" value="Pedro Duarte" />
</Field>
<Field>
<Label for="username-1">Username</Label>
<Input id="username-1" name="username" value="@peduarte" />
</Field>
</FieldGroup>
<DialogFooter>
<DialogClose variant="outline">Cancel</DialogClose>
<Button type="submit">Save changes</Button>
</DialogFooter>
</DialogContent>
</form>
</Dialog>Installation
npx shadcn@latest add @fulldev/dialog
Usage
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
<Dialog>
<DialogTrigger>Open</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you absolutely sure?</DialogTitle>
<DialogDescription>
This action cannot be undone. This will permanently delete your account
and remove your data from our servers.
</DialogDescription>
</DialogHeader>
</DialogContent>
</Dialog>
DialogTrigger and DialogClose render a Button and take its props, such as
variant="outline". DialogContent moves to document.body while open, so a
form around the whole dialog does not contain the content: put the form
inside DialogContent when the dialog submits.
Composition
Dialog
├── DialogTrigger
└── DialogContent
├── DialogHeader
│ ├── DialogTitle
│ └── DialogDescription
└── DialogFooter
Custom Close Button
Replace the default close control with your own DialogClose.
Share link
Anyone who has this link will be able to view this.
---
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
---
<Dialog>
<DialogTrigger variant="outline">Share</DialogTrigger>
<DialogContent class="sm:max-w-md">
<DialogHeader>
<DialogTitle>Share link</DialogTitle>
<DialogDescription>
Anyone who has this link will be able to view this.
</DialogDescription>
</DialogHeader>
<div class="flex items-center gap-2">
<div class="grid flex-1 gap-2">
<Label for="link" class="sr-only">
Link
</Label>
<Input
id="link"
value="https://ui.shadcn.com/docs/installation"
readonly
/>
</div>
</div>
<DialogFooter class="sm:justify-start">
<DialogClose>Close</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>No Close Button
Use showCloseButton={false} to hide the close button.
No Close Button
This dialog doesn't have a close button in the top-right corner.
---
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
---
<Dialog>
<DialogTrigger variant="outline">No Close Button</DialogTrigger>
<DialogContent showCloseButton={false}>
<DialogHeader>
<DialogTitle>No Close Button</DialogTitle>
<DialogDescription>
This dialog doesn't have a close button in the top-right corner.
</DialogDescription>
</DialogHeader>
</DialogContent>
</Dialog>Sticky Footer
Keep actions visible while the content scrolls.
Sticky Footer
This dialog has a sticky footer that stays visible while the content scrolls.
---
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
---
<Dialog>
<DialogTrigger variant="outline">Sticky Footer</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Sticky Footer</DialogTitle>
<DialogDescription>
This dialog has a sticky footer that stays visible while the content
scrolls.
</DialogDescription>
</DialogHeader>
<div class="-mx-4 no-scrollbar max-h-[50vh] overflow-y-auto px-4">
{Array.from({ length: 10 }).map(() => (
<p class="mb-4 leading-normal">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
</p>
))}
</div>
<DialogFooter>
<DialogClose variant="outline">Close</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>Scrollable Content
Long content can scroll while the header stays in view.
Scrollable Content
This is a dialog with scrollable content.
---
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
---
<Dialog>
<DialogTrigger variant="outline">Scrollable Content</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Scrollable Content</DialogTitle>
<DialogDescription>
This is a dialog with scrollable content.
</DialogDescription>
</DialogHeader>
<div class="-mx-4 no-scrollbar max-h-[50vh] overflow-y-auto px-4">
{Array.from({ length: 10 }).map(() => (
<p class="mb-4 leading-normal">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
</p>
))}
</div>
</DialogContent>
</Dialog>RTL
---
import { Button } from "@/components/ui/button"
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Field, FieldGroup } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
const translations = {
en: {
dir: "ltr",
values: {
openDialog: "Open Dialog",
editProfile: "Edit profile",
description:
"Make changes to your profile here. Click save when you're done.",
name: "Name",
username: "Username",
cancel: "Cancel",
saveChanges: "Save changes",
},
},
ar: {
dir: "rtl",
values: {
openDialog: "فتح الحوار",
editProfile: "تعديل الملف الشخصي",
description:
"قم بإجراء تغييرات على ملفك الشخصي هنا. انقر فوق حفظ عند الانتهاء.",
name: "الاسم",
username: "اسم المستخدم",
cancel: "إلغاء",
saveChanges: "حفظ التغييرات",
},
},
he: {
dir: "rtl",
values: {
openDialog: "פתח דיאלוג",
editProfile: "ערוך פרופיל",
description: "בצע שינויים בפרופיל שלך כאן. לחץ על שמור כשתסיים.",
name: "שם",
username: "שם משתמש",
cancel: "בטל",
saveChanges: "שמור שינויים",
},
},
} as const
const language = "ar"
const { dir, values: t } = translations[language]
---
<Dialog>
<form>
<DialogTrigger variant="outline">{t.openDialog}</DialogTrigger>
<DialogContent
class="sm:max-w-sm"
dir={dir}
data-lang={dir === "rtl" ? language : undefined}
>
<DialogHeader>
<DialogTitle>{t.editProfile}</DialogTitle>
<DialogDescription>{t.description}</DialogDescription>
</DialogHeader>
<FieldGroup>
<Field>
<Label for="name-rtl-1">{t.name}</Label>
<Input id="name-rtl-1" name="name" value="Pedro Duarte" />
</Field>
<Field>
<Label for="username-rtl-1">{t.username}</Label>
<Input id="username-rtl-1" name="username" value="@peduarte" />
</Field>
</FieldGroup>
<DialogFooter>
<DialogClose variant="outline">{t.cancel}</DialogClose>
<Button type="submit">{t.saveChanges}</Button>
</DialogFooter>
</DialogContent>
</form>
</Dialog>API Reference
Source: src/components/ui/dialog
Dialog prop | Type | Default |
|---|---|---|
defaultOpen | boolean | false |
closeOnClickOutside | boolean | true |
closeOnEscape | boolean | true |
lockScroll | boolean | true |
alertDialog | boolean | false |
DialogContent prop | Type | Default |
|---|---|---|
showCloseButton | boolean | true |
Open or close a dialog from a script with
root.dispatchEvent(new CustomEvent("dialog:set", { detail: { open: true } }))
and listen for dialog:change. See the
Data Slot docs
for all events and data attributes.