Components
Dialog
A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.
Loading...
Installation
CLI
npx shadcn@latest add https://exawizards.com/exabase/design/registry/dialog.jsonManual
Copy and paste the following code into your project.
"use client"
import * as React from "react"
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"
import { XmarkLargeIcon } from "@exawizards/exabase-design-system-icons-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { ScrollArea, ScrollContent } from "@/components/ui/scroll-area"
function Dialog({ ...props }: DialogPrimitive.Root.Props) {
return <DialogPrimitive.Root data-slot="dialog" {...props} />
}
function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
}
function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
}
function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
}
function DialogOverlay({
className,
...props
}: DialogPrimitive.Backdrop.Props) {
return (
<DialogPrimitive.Backdrop
data-slot="dialog-overlay"
className={cn(
"fixed inset-0 isolate z-50 bg-black/50 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
className
)}
{...props}
/>
)
}
function DialogContent({
className,
children,
showCloseButton = true,
...props
}: DialogPrimitive.Popup.Props & {
showCloseButton?: boolean
}) {
return (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Viewport
data-slot="dialog-viewport"
className="fixed inset-0 z-50"
>
<ScrollArea
style={{ position: undefined }}
className="h-full overscroll-contain"
>
<ScrollContent className="flex min-h-full items-center justify-center p-4">
<DialogPrimitive.Popup
data-slot="dialog-content"
className={cn(
"relative grid w-full max-w-[480px] gap-4 rounded-xl bg-background p-6 text-sm text-foreground outline outline-border data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
className
)}
{...props}
>
{children}
{showCloseButton && (
<DialogPrimitive.Close
data-slot="dialog-close"
render={
<Button
variant="ghost"
className="absolute top-3 right-3"
size="icon-sm"
/>
}
>
<XmarkLargeIcon />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
)}
</DialogPrimitive.Popup>
</ScrollContent>
</ScrollArea>
</DialogPrimitive.Viewport>
</DialogPortal>
)
}
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="dialog-header"
className={cn("flex flex-col gap-2", className)}
{...props}
/>
)
}
function DialogFooter({
className,
showCloseButton = false,
children,
...props
}: React.ComponentProps<"div"> & {
showCloseButton?: boolean
}) {
return (
<div
data-slot="dialog-footer"
className={cn("flex flex-row justify-end gap-2", className)}
{...props}
>
{children}
{showCloseButton && (
<DialogPrimitive.Close render={<Button variant="outline" />}>
Close
</DialogPrimitive.Close>
)}
</div>
)
}
function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
return (
<DialogPrimitive.Title
data-slot="dialog-title"
className={cn("pr-8 text-lg font-semibold", className)}
{...props}
/>
)
}
function DialogDescription({
className,
...props
}: DialogPrimitive.Description.Props) {
return (
<DialogPrimitive.Description
data-slot="dialog-description"
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
)
}
export {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogOverlay,
DialogPortal,
DialogTitle,
DialogTrigger,
}
Usage
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"<Dialog>
<DialogTrigger>Open</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure 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>Examples
Basic
Loading...
Custom width
<DialogContent className="max-w-2xl">Loading...
Long content
When the content of the dialog is long, the outside of the dialog becomes scrollable.
When the first focusable element inside the dialog content is out of view, the dialog may open at an unexpected scroll position.
To avoid this, pass a ref to DialogContent and set it as the initialFocus.
const ref = useRef(null);
<DialogContent ref={ref} initialFocus={ref}>Loading...
Scrollable content
To make the content scrollable, set max-h and grid-rows on DialogContent, and wrap the scrollable area with ScrollArea.
When there is less content, DialogContent shrinks to fit. When there is more content, the ScrollArea becomes scrollable.
<DialogContent className="max-h-[calc(100dvh---spacing(8))] grid-rows-[auto_1fr_auto]">
...
<ScrollArea className="overflow-hidden">
...
</ScrollArea>
...Loading...
No close button
<DialogContent showCloseButton={false}>Loading...
API
See the Base UI documentation for more information.