- Accordion
- Alert
- Alert Dialog
- Autocomplete
- Avatar
- Badge
- Breadcrumb
- Button
- Card
- Checkbox
- Checkbox Group
- Collapsible
- Combobox
- CommandNew
- Dialog
- Empty
- Field
- Fieldset
- Form
- Frame
- Group
- Input
- Input Group
- Kbd
- Label
- Menu
- Meter
- Number Field
- Pagination
- Popover
- Preview Card
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Skeleton
- Slider
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Toolbar
- Tooltip
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 shadcn@latest add @coss/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>API Reference
Dialog
Root component. Alias for Dialog.Root from Base UI.
DialogTrigger
Trigger button that opens the dialog. Alias for Dialog.Trigger from Base UI.
DialogPopup
Popup container that displays the dialog content. Also exported as DialogContent.
| Prop | Type | Default | Description |
|---|---|---|---|
showCloseButton | boolean | true | When true, displays a close button in the top-right corner |
bottomStickOnMobile | boolean | true | When true, sticks to the bottom of the screen on mobile devices |
DialogHeader
Container for the dialog title and description.
DialogFooter
Footer section for action buttons.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "bare" | "default" | Controls the footer styling. default includes border and background, bare removes them |
Example:
// 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>DialogTitle
Title component. Alias for Dialog.Title from Base UI.
DialogDescription
Description component. Alias for Dialog.Description from Base UI.
DialogPanel
Scrollable content container. Automatically wraps content in a ScrollArea component.
| Prop | Type | Default | Description |
|---|---|---|---|
scrollFade | boolean | true | When true, shows a fade effect at scroll edges |
Example:
<DialogPanel>
{/* Long content that will scroll if it exceeds the dialog height */}
<div>...</div>
</DialogPanel>DialogClose
Close button component. Alias for Dialog.Close from Base UI.
DialogPortal
Portal component for rendering outside the DOM hierarchy. Alias for Dialog.Portal from Base UI.
DialogBackdrop
Backdrop/overlay component. Also exported as DialogOverlay. Alias for Dialog.Backdrop from Base UI.
DialogViewport
Viewport component for positioning. Alias for Dialog.Viewport from Base UI.
Examples
Open from a Menu
"use client";
import { useState } 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] = 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">[email protected]</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="[email protected]" type="text" />
</Field>
</DialogPanel>
<DialogFooter>
<DialogClose render={<Button variant="ghost" />}>
Cancel
</DialogClose>
<Button type="submit">Save changes</Button>
</DialogFooter>
</DialogPopup>
</Dialog>
</DialogFooter>
</DialogPopup>
</Dialog>
);
}
Close Confirmation
"use client";
import { useState } from "react";
import {
AlertDialog,
AlertDialogClose,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogPopup,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogClose,
DialogDescription,
DialogFooter,
DialogHeader,
DialogPanel,
DialogPopup,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Field } from "@/components/ui/field";
import { Form } from "@/components/ui/form";
import { Textarea } from "@/components/ui/textarea";
export default function Particle() {
const [dialogOpen, setDialogOpen] = useState(false);
const [confirmOpen, setConfirmOpen] = useState(false);
const [value, setValue] = useState("");
return (
<Dialog
onOpenChange={(o) => {
if (!o && value) {
setConfirmOpen(true);
} else {
setDialogOpen(o);
}
}}
open={dialogOpen}
>
<DialogTrigger render={<Button variant="outline" />}>
Compose
</DialogTrigger>
<DialogPopup showCloseButton={false}>
<DialogHeader>
<DialogTitle>New message</DialogTitle>
<DialogDescription>Type something and try closing.</DialogDescription>
</DialogHeader>
<Form
className="contents"
onSubmit={(event) => {
event.preventDefault();
// Close the dialog when submitting
setDialogOpen(false);
}}
>
<DialogPanel>
<Field>
<Textarea
onChange={(e) => setValue(e.target.value)}
value={value}
/>
</Field>
</DialogPanel>
<DialogFooter>
<DialogClose render={<Button variant="ghost" />}>
Cancel
</DialogClose>
<Button
onClick={() => {
setValue("");
setDialogOpen(false);
}}
>
Send
</Button>
</DialogFooter>
</Form>
</DialogPopup>
{/* Confirmation dialog */}
<AlertDialog onOpenChange={setConfirmOpen} open={confirmOpen}>
<AlertDialogPopup>
<AlertDialogHeader>
<AlertDialogTitle>Discard changes?</AlertDialogTitle>
<AlertDialogDescription>
Your message will be lost.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogClose render={<Button variant="ghost" />}>
Go back
</AlertDialogClose>
<Button
onClick={() => {
setConfirmOpen(false);
setValue("");
setDialogOpen(false);
}}
>
Discard
</Button>
</AlertDialogFooter>
</AlertDialogPopup>
</AlertDialog>
</Dialog>
);
}