Data Display
Forms
Navigation
Dialog
A popup that opens on top of the entire page.
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogClose,
DialogDescription,
DialogFooter,
DialogHeader,
DialogPanel,
DialogPopup,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Field, FieldLabel } from "@/components/ui/field";
import { Form } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
export default function Particle() {
return (
<Dialog>
<DialogTrigger render={<Button variant="outline" />}>
Open Dialog
</DialogTrigger>
<DialogPopup className="sm:max-w-sm">
<Form className="contents">
<DialogHeader>
<DialogTitle>Edit profile</DialogTitle>
<DialogDescription>
Make changes to your profile here. Click save when you're
done.
</DialogDescription>
</DialogHeader>
<DialogPanel className="grid gap-4">
<Field>
<FieldLabel>Name</FieldLabel>
<Input defaultValue="Margaret Welsh" type="text" />
</Field>
<Field>
<FieldLabel>Username</FieldLabel>
<Input defaultValue="@maggie.welsh" type="text" />
</Field>
</DialogPanel>
<DialogFooter>
<DialogClose render={<Button variant="ghost" />}>
Cancel
</DialogClose>
<Button type="submit">Save</Button>
</DialogFooter>
</Form>
</DialogPopup>
</Dialog>
);
}
Installation
pnpm dlx cnippet@latest add dialog
Usage
import {
Dialog,
DialogDescription,
DialogPanel,
DialogFooter,
DialogHeader,
DialogPopup,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"<Dialog>
<DialogTrigger>Open Dialog</DialogTrigger>
<DialogPopup>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
<DialogDescription>Dialog Description</DialogDescription>
</DialogHeader>
<DialogPanel>Content</DialogPanel>
<DialogFooter>
<DialogClose>Close</DialogClose>
</DialogFooter>
</DialogPopup>
</Dialog>DialogFooter Variant
The DialogFooter component supports a variant prop to control its styling:
default(default): Includes a border-top, background color, and paddingbare: Removes the border and background for a minimal appearance
// Default variant (with border and background)
<DialogFooter>
<DialogClose>Cancel</DialogClose>
<Button>Save</Button>
</DialogFooter>
// Bare variant (no border or background)
<DialogFooter variant="bare">
<DialogClose>Cancel</DialogClose>
<Button>Save</Button>
</DialogFooter>DialogPanel Scrolling
The DialogPanel component automatically wraps its content in a ScrollArea component. This means that if the content exceeds the dialog's maximum height, it will become scrollable automatically. The scrollbar will appear when needed, providing a smooth scrolling experience.
<DialogPanel>
{/* Long content that will scroll if it exceeds the dialog height */}
<div>...</div>
</DialogPanel>Examples
Open from a Menu
"use client";
import * as React from "react";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogClose,
DialogDescription,
DialogFooter,
DialogHeader,
DialogPopup,
DialogTitle,
} from "@/components/ui/dialog";
import {
Menu,
MenuItem,
MenuPopup,
MenuTrigger,
} from "@/components/ui/menu";
export default function Particle() {
const [dialogOpen, setDialogOpen] = React.useState(false);
return (
<>
<Menu>
<MenuTrigger render={<Button variant="outline" />}>
Open menu
</MenuTrigger>
<MenuPopup align="start">
<MenuItem onClick={() => setDialogOpen(true)}>Open dialog</MenuItem>
</MenuPopup>
</Menu>
<Dialog onOpenChange={setDialogOpen} open={dialogOpen}>
<DialogPopup>
<DialogHeader>
<DialogTitle>Settings</DialogTitle>
<DialogDescription>Change your preferences</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose render={<Button variant="ghost" />}>Close</DialogClose>
</DialogFooter>
</DialogPopup>
</Dialog>
</>
);
}
Dialog with Bare Footer
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogClose,
DialogDescription,
DialogFooter,
DialogHeader,
DialogPanel,
DialogPopup,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Field, FieldLabel } from "@/components/ui/field";
import { Form } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
export default function Particle() {
return (
<Dialog>
<DialogTrigger render={<Button variant="outline" />}>
Open Dialog
</DialogTrigger>
<DialogPopup className="sm:max-w-sm">
<Form className="contents">
<DialogHeader>
<DialogTitle>Edit profile</DialogTitle>
<DialogDescription>
Make changes to your profile here. Click save when you're
done.
</DialogDescription>
</DialogHeader>
<DialogPanel className="grid gap-4">
<Field>
<FieldLabel>Name</FieldLabel>
<Input defaultValue="Margaret Welsh" type="text" />
</Field>
<Field>
<FieldLabel>Username</FieldLabel>
<Input defaultValue="@maggie.welsh" type="text" />
</Field>
</DialogPanel>
<DialogFooter variant="bare">
<DialogClose render={<Button variant="ghost" />}>
Cancel
</DialogClose>
<Button type="submit">Save</Button>
</DialogFooter>
</Form>
</DialogPopup>
</Dialog>
);
}
Dialog with scroll inside
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogClose,
DialogFooter,
DialogHeader,
DialogPanel,
DialogPopup,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
export default function Particle() {
return (
<Dialog>
<DialogTrigger render={<Button variant="outline" />}>
Terms & Conditions
</DialogTrigger>
<DialogPopup className="sm:max-w-md" showCloseButton={false}>
<DialogHeader>
<DialogTitle>Terms & Conditions</DialogTitle>
</DialogHeader>
<DialogPanel>
<div className="space-y-4 [&_strong]:font-semibold [&_strong]:text-foreground">
<div className="space-y-4">
<div className="space-y-1">
<p>
<strong>Acceptance of Terms</strong>
</p>
<p>
By accessing and using this website, users agree to comply
with and be bound by these Terms of Service. Users who do not
agree with these terms should discontinue use of the website
immediately.
</p>
</div>
<div className="space-y-1">
<p>
<strong>User Account Responsibilities</strong>
</p>
<p>
Users are responsible for maintaining the confidentiality of
their account credentials. Any activities occurring under a
user's account are the sole responsibility of the account
holder. Users must notify the website administrators
immediately of any unauthorized account access.
</p>
</div>
<div className="space-y-1">
<p>
<strong>Content Usage and Restrictions</strong>
</p>
<p>
The website and its original content are protected by
intellectual property laws. Users may not reproduce,
distribute, modify, create derivative works, or commercially
exploit any content without explicit written permission from
the website owners.
</p>
</div>
<div className="space-y-1">
<p>
<strong>Limitation of Liability</strong>
</p>
<p>
The website provides content “as is” without any
warranties. The website owners shall not be liable for direct,
indirect, incidental, consequential, or punitive damages
arising from user interactions with the platform.
</p>
</div>
<div className="space-y-1">
<p>
<strong>User Conduct Guidelines</strong>
</p>
<ul className="list-disc pl-6">
<li>Not upload harmful or malicious content</li>
<li>Respect the rights of other users</li>
<li>
Avoid activities that could disrupt website functionality
</li>
<li>Comply with applicable local and international laws</li>
</ul>
</div>
<div className="space-y-1">
<p>
<strong>Modifications to Terms</strong>
</p>
<p>
The website reserves the right to modify these terms at any
time. Continued use of the website after changes constitutes
acceptance of the new terms.
</p>
</div>
<div className="space-y-1">
<p>
<strong>Termination Clause</strong>
</p>
<p>
The website may terminate or suspend user access without prior
notice for violations of these terms or for any other reason
deemed appropriate by the administration.
</p>
</div>
<div className="space-y-1">
<p>
<strong>Governing Law</strong>
</p>
<p>
These terms are governed by the laws of the jurisdiction where
the website is primarily operated, without regard to conflict
of law principles.
</p>
</div>
</div>
</div>
</DialogPanel>
<DialogFooter>
<DialogClose render={<Button variant="ghost" />}>Cancel</DialogClose>
<Button type="button">I agree</Button>
</DialogFooter>
</DialogPopup>
</Dialog>
);
}
Nested Dialogs
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogClose,
DialogDescription,
DialogFooter,
DialogHeader,
DialogPanel,
DialogPopup,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Field, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
export default function Particle() {
return (
<Dialog>
<DialogTrigger render={<Button variant="outline" />}>
Open parent
</DialogTrigger>
<DialogPopup showCloseButton={false}>
<DialogHeader>
<DialogTitle>Manage team member</DialogTitle>
<DialogDescription>
View and manage a user in your team.
</DialogDescription>
</DialogHeader>
<DialogPanel className="grid gap-4">
<div className="grid gap-1">
<p className="text-muted-foreground text-sm">Name</p>
<p className="font-medium text-sm">Bora Baloglu</p>
</div>
<div className="grid gap-1">
<p className="text-muted-foreground text-sm">Email</p>
<p className="font-medium text-sm">bora@example.com</p>
</div>
</DialogPanel>
<DialogFooter>
<Dialog>
<DialogTrigger render={<Button variant="outline" />}>
Edit details
</DialogTrigger>
<DialogPopup showCloseButton={false}>
<DialogHeader>
<DialogTitle>Edit details</DialogTitle>
<DialogDescription>
Make changes to the member's information.
</DialogDescription>
</DialogHeader>
<DialogPanel className="grid gap-4">
<Field>
<FieldLabel>Name</FieldLabel>
<Input defaultValue="Bora Baloglu" type="text" />
</Field>
<Field>
<FieldLabel>Email</FieldLabel>
<Input defaultValue="bora@example.com" type="text" />
</Field>
</DialogPanel>
<DialogFooter>
<DialogClose render={<Button variant="ghost" />}>
Cancel
</DialogClose>
<Button type="submit">Save changes</Button>
</DialogFooter>
</DialogPopup>
</Dialog>
</DialogFooter>
</DialogPopup>
</Dialog>
);
}