Sheet
Overlay & FeedbackBottom sheet overlay with header and content.
Preview
Usage
example.jsx
import { Sheet, SheetHeader, SheetTitle, SheetDescription, SheetContent, SheetFooter } from "@/components/ui/sheet";
export default function Example() {
return <Sheet />;
}Source Code
Copy this file into components/ui/sheet.jsx in your project.
sheet.jsx
"use client";
import { forwardRef, useEffect } from "react";
import { cn } from "@/lib/utils";
const Sheet = forwardRef(({ className, open, onClose, side = "right", children, ...props }, ref) => {
useEffect(() => {
if (open) document.body.style.overflow = "hidden";
return () => { document.body.style.overflow = ""; };
}, [open]);
if (!open) return null;
return (
<div className="fixed inset-0 z-50">
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm" onClick={onClose} />
<div ref={ref}
className={cn("fixed z-50 flex flex-col border bg-background shadow-lg transition-transform duration-300",
side === "right" && "inset-y-0 right-0 h-full w-3/4 max-w-sm border-l",
side === "left" && "inset-y-0 left-0 h-full w-3/4 max-w-sm border-r",
side === "top" && "inset-x-0 top-0 border-b",
side === "bottom" && "inset-x-0 bottom-0 border-t",
className
)}
{...props}
>
<button onClick={onClose} className="absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100">
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" /></svg>
</button>
{children}
</div>
</div>
);
});
Sheet.displayName = "Sheet";
const SheetHeader = forwardRef(({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex flex-col space-y-2 p-6 pb-0", className)} {...props} />
));
SheetHeader.displayName = "SheetHeader";
const SheetTitle = forwardRef(({ className, ...props }, ref) => (
<h2 ref={ref} className={cn("text-lg font-semibold text-foreground", className)} {...props} />
));
SheetTitle.displayName = "SheetTitle";
const SheetDescription = forwardRef(({ className, ...props }, ref) => (
<p ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />
));
SheetDescription.displayName = "SheetDescription";
const SheetContent = forwardRef(({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex-1 overflow-auto p-6", className)} {...props} />
));
SheetContent.displayName = "SheetContent";
const SheetFooter = forwardRef(({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex flex-col-reverse gap-2 p-6 pt-0 sm:flex-row sm:justify-end", className)} {...props} />
));
SheetFooter.displayName = "SheetFooter";
export { Sheet, SheetHeader, SheetTitle, SheetDescription, SheetContent, SheetFooter };
Quick Install
Make sure you have the cn() utility set up. It requires clsx and tailwind-merge.
npm install clsx tailwind-merge