A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.
1import { Button } from "@/components/ui/button";2import {3 Dialog,4 DialogClose,Installation
pnpm dlx sprawlify@latest add dialognpx sprawlify@latest add dialogyarn sprawlify@latest add dialogbunx --bun sprawlify@latest add dialog
Install the following dependencies:
pnpm add @sprawlify/primitives @sprawlify/reactnpm install @sprawlify/primitives @sprawlify/reactyarn add @sprawlify/primitives @sprawlify/reactbun add @sprawlify/primitives @sprawlify/react
Add the following files to your project:
1"use client";23import * as React from "react";4import { XIcon } from "lucide-react";5import { Dialog as DialogPrimitive } from "@sprawlify/react/dialog";67import { cn } from "@/lib/utils";8import { Button } from "@/components/ui/button";9import { Portal } from "@sprawlify/react/portal";10import { sprawlify } from "@sprawlify/react";1112function Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>) {13 return <DialogPrimitive.Root data-slot="dialog" {...props} />;14}1516function DialogTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {17 return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;18}1920function DialogPortal({ ...props }: React.ComponentProps<typeof Portal>) {21 return <Portal data-slot="dialog-portal" {...props} />;22}2324function DialogClose({ ...props }: React.ComponentProps<typeof DialogPrimitive.CloseTrigger>) {25 return <DialogPrimitive.CloseTrigger data-slot="dialog-close" {...props} />;26}2728function DialogOverlay({29 className,30 ...props31}: React.ComponentProps<typeof DialogPrimitive.Backdrop>) {32 return (33 <DialogPrimitive.Backdrop34 data-slot="dialog-overlay"35 className={cn(36 "fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=closed]:animate-out data-[state=closed]:fade-out-0",37 className,38 )}39 {...props}40 />41 );42}4344function DialogContent({45 className,46 children,47 showCloseButton = true,48 ...props49}: React.ComponentProps<typeof DialogPrimitive.Content> & {50 showCloseButton?: boolean;51}) {52 return (53 <DialogPortal>54 <DialogOverlay />55 <DialogPrimitive.Content56 data-slot="dialog-content"57 className={cn(58 "fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",59 className,60 )}61 {...props}62 >63 {children}64 {showCloseButton && (65 <DialogPrimitive.CloseTrigger data-slot="dialog-close" asChild>66 <Button variant="ghost" className="absolute top-2 right-2" size="icon-sm">67 <XIcon />68 <span className="sr-only">Close</span>69 </Button>70 </DialogPrimitive.CloseTrigger>71 )}72 </DialogPrimitive.Content>73 </DialogPortal>74 );75}7677function DialogHeader({ className, ...props }: React.ComponentProps<typeof sprawlify.div>) {78 return (79 <sprawlify.div80 data-slot="dialog-header"81 className={cn("flex flex-col gap-2", className)}82 {...props}83 />84 );85}8687function DialogFooter({88 className,89 showCloseButton = false,90 children,91 ...props92}: React.ComponentProps<typeof sprawlify.div> & {93 showCloseButton?: boolean;94}) {95 return (96 <sprawlify.div97 data-slot="dialog-footer"98 className={cn(99 "-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 sm:flex-row sm:justify-end",100 className,101 )}102 {...props}103 >104 {children}105 {showCloseButton && (106 <DialogPrimitive.CloseTrigger asChild>107 <Button variant="outline">Close</Button>108 </DialogPrimitive.CloseTrigger>109 )}110 </sprawlify.div>111 );112}113114function DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {115 return (116 <DialogPrimitive.Title117 data-slot="dialog-title"118 className={cn("cn-font-heading text-base leading-none font-medium", className)}119 {...props}120 />121 );122}123124function DialogDescription({125 className,126 ...props127}: React.ComponentProps<typeof DialogPrimitive.Description>) {128 return (129 <DialogPrimitive.Description130 data-slot="dialog-description"131 className={cn(132 "text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",133 className,134 )}135 {...props}136 />137 );138}139140export {141 Dialog,142 DialogClose,143 DialogContent,144 DialogDescription,145 DialogFooter,146 DialogHeader,147 DialogOverlay,148 DialogPortal,149 DialogTitle,150 DialogTrigger,151};152Update the import paths to match your project setup.
Usage
1import {
2 Dialog,
3 DialogContent,
4 DialogDescription,
5 DialogHeader,
6 DialogTitle,
7 DialogTrigger,
8} from "@/components/ui/dialog"1<Dialog>
2 <DialogTrigger>Open</DialogTrigger>
3 <DialogContent>
4 <DialogHeader>
5 <DialogTitle>Are you absolutely sure?</DialogTitle>
6 <DialogDescription>
7 This action cannot be undone. This will permanently delete your account
8 and remove your data from our servers.
9 </DialogDescription>
10 </DialogHeader>
11 </DialogContent>
12</Dialog>Examples
Custom Close Button
Replace the default close control with your own button.
1import { Button } from "@/components/ui/button";2import {3 Dialog,4 DialogClose,No Close Button
Use showCloseButton={false} to hide the close button.
1import { Button } from "@/components/ui/button";2import {3 Dialog,4 DialogContent,Scrollable Content
Long content can scroll while the header stays in view.
1import { Button } from "@/components/ui/button";2import {3 Dialog,4 DialogContent,Sticky Footer
Keep actions visible while the content scrolls.
1import { Button } from "@/components/ui/button";2import {3 Dialog,4 DialogClose,On This Page
InstallationUsageExamplesCustom Close ButtonNo Close ButtonScrollable ContentSticky FooterGet PRO
Need premium blocks and templates? Upgrade to PRO and get access.