Components
- Accordion
- Alert
- Alert Dialog
- Autocomplete
- Avatar
- Badge
- Breadcrumb
- Button
- Card
- Checkbox
- Checkbox Group
- Collapsible
- Combobox
- Dialog
- EmptyNew
- Field
- Fieldset
- Form
- Frame
- Group
- Input
- Input GroupNew
- KbdNew
- Label
- Menu
- Meter
- Number Field
- Pagination
- Popover
- Preview Card
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- SkeletonNew
- Slider
- SpinnerNew
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Toolbar
- Tooltip
Resources
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>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">[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 * as React 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] = React.useState(false);
const [confirmOpen, setConfirmOpen] = React.useState(false);
const [value, setValue] = React.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>
);
}
Comparing with Radix / shadcn
If you’re already familiar with Radix UI and shadcn/ui, this guide highlights the small differences and similarities so you can get started with coss ui quickly.
Quick Checklist
- Replace
asChild→renderonDialogTriggerand closing buttons - Prefer
DialogPopup;DialogContentremains for legacy - Use
DialogPanelto wrap main content betweenDialogHeaderandDialogFooter - If you used
asChildon any other parts, switch to therenderprop
Comparison Example
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Show Dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
<DialogDescription>Dialog Description</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="ghost">Cancel</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog><Dialog>
<DialogTrigger render={<Button variant="outline" />}>
Show Dialog
</DialogTrigger>
<DialogPopup>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
<DialogDescription>Dialog Description</DialogDescription>
</DialogHeader>
<DialogPanel>Content</DialogPanel>
<DialogFooter>
<DialogClose render={<Button variant="ghost" />}>Cancel</DialogClose>
</DialogFooter>
</DialogPopup>
</Dialog>