Dialog
A popup that opens on top of the page.
import { buttonVariants } from "@arshad/ui/components/button";
import { Dialog } from "@arshad/ui/components/dialog";
export function Basic() {
return (
<Dialog.Root>
<Dialog.Trigger className={buttonVariants({ variant: "outline" })}>
Archive project
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Backdrop />
<Dialog.Viewport>
<Dialog.Popup>
<Dialog.Header>
<Dialog.Title>Archive this project?</Dialog.Title>
<Dialog.Description>
It moves to Archived and stops syncing. You can restore it at any time.
</Dialog.Description>
</Dialog.Header>
<Dialog.Footer>
<Dialog.Close className={buttonVariants({ variant: "outline" })}>Cancel</Dialog.Close>
<Dialog.Close className={buttonVariants()}>Archive</Dialog.Close>
</Dialog.Footer>
</Dialog.Popup>
</Dialog.Viewport>
</Dialog.Portal>
</Dialog.Root>
);
}Scrollable
Long content scrolls inside Dialog.Body, and a hairline marks each edge it is cut off at.
import { buttonVariants } from "@arshad/ui/components/button";
import { Dialog } from "@arshad/ui/components/dialog";
const terms = [
{
title: "Your account",
body: "You’re responsible for what happens under your account. Keep your password private and tell us right away if someone else gets in.",
},
{
title: "Your content",
body: "You own what you upload. You let us store, display, and back it up so the service works.",
},
{
title: "Acceptable use",
body: "Don’t use the service to break the law, send spam, or interfere with other people’s work.",
},
{
title: "Payments",
body: "Paid plans renew each month until you cancel. Prices include tax where the law requires it.",
},
{
title: "Cancelling",
body: "Cancel at any time from Settings. Your plan stays active until the end of the period you paid for.",
},
{
title: "Refunds",
body: "We refund a charge in full if you cancel within 14 days of it.",
},
{
title: "Privacy",
body: "We collect only what we need to run the service. The privacy policy explains what we keep and for how long.",
},
{
title: "Availability",
body: "We aim to keep the service running at all times, but outages and maintenance happen.",
},
{
title: "Changes to these terms",
body: "We email you at least 30 days before a change takes effect.",
},
{
title: "Ending the agreement",
body: "We may suspend an account that breaks these terms. You can still export your data for 30 days.",
},
{
title: "Liability",
body: "Our liability is limited to what you paid us in the last 12 months.",
},
{
title: "Contact",
body: "Send questions about these terms to legal@example.com.",
},
];
export function Scrollable() {
return (
<Dialog.Root>
<Dialog.Trigger className={buttonVariants({ variant: "outline" })}>
Review terms
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Backdrop />
<Dialog.Viewport>
<Dialog.Popup className="max-w-lg">
<Dialog.Header>
<Dialog.Title>Terms of service</Dialog.Title>
<Dialog.Description>Read these before you continue.</Dialog.Description>
</Dialog.Header>
<Dialog.Body className="flex flex-col gap-6">
{terms.map((term) => (
<section key={term.title} className="flex flex-col gap-1">
<h3 className="font-medium">{term.title}</h3>
<p className="text-pretty text-neutral-600 dark:text-neutral-400">{term.body}</p>
</section>
))}
</Dialog.Body>
<Dialog.Footer>
<Dialog.Close className={buttonVariants({ variant: "outline" })}>
Decline
</Dialog.Close>
<Dialog.Close className={buttonVariants()}>Accept</Dialog.Close>
</Dialog.Footer>
</Dialog.Popup>
</Dialog.Viewport>
</Dialog.Portal>
</Dialog.Root>
);
}Nested
Open a dialog from inside another.
import { buttonVariants } from "@arshad/ui/components/button";
import { Dialog } from "@arshad/ui/components/dialog";
export function Nested() {
return (
<Dialog.Root>
<Dialog.Trigger className={buttonVariants({ variant: "outline" })}>
Manage plan
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Backdrop />
<Dialog.Viewport>
<Dialog.Popup>
<Dialog.Header>
<Dialog.Title>Pro plan</Dialog.Title>
<Dialog.Description>Billed monthly and renews automatically.</Dialog.Description>
</Dialog.Header>
<Dialog.Footer>
<Dialog.Root>
<Dialog.Trigger className={buttonVariants({ variant: "outline" })}>
Cancel plan
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Viewport>
<Dialog.Popup>
<Dialog.Header>
<Dialog.Title>Cancel your Pro plan?</Dialog.Title>
<Dialog.Description>
You keep Pro until the end of this billing period, then move to the free
Hobby plan.
</Dialog.Description>
</Dialog.Header>
<Dialog.Footer>
<Dialog.Close className={buttonVariants({ variant: "outline" })}>
Keep Pro
</Dialog.Close>
<Dialog.Close className={buttonVariants({ color: "danger" })}>
Cancel plan
</Dialog.Close>
</Dialog.Footer>
</Dialog.Popup>
</Dialog.Viewport>
</Dialog.Portal>
</Dialog.Root>
<Dialog.Close className={buttonVariants()}>Done</Dialog.Close>
</Dialog.Footer>
</Dialog.Popup>
</Dialog.Viewport>
</Dialog.Portal>
</Dialog.Root>
);
}API
Dialog.Header, Dialog.Body, and Dialog.Footer lay out the popup. Every other part takes the props of its Base UI Dialog counterpart.