A sheet component that slides in from the side of the screen, used for displaying additional content or actions without taking up the full screen.
import Image from "next/image";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet";
export function SheetDemo() {
return (
<Sheet>
<SheetTrigger render={<Button variant="outline">Open</Button>} />
<SheetContent>
<SheetHeader>
<SheetTitle>Edit profile</SheetTitle>
<SheetDescription>
Update the details below and click save to apply changes.
</SheetDescription>
</SheetHeader>
<div className="flex flex-col gap-4 px-4">
<div className="relative aspect-video w-full overflow-hidden">
<Image
src="/images/dialog-demo-image.jpg"
alt="dialog-placeholder"
priority
className="rounded-md"
objectFit="cover"
fill
/>
</div>
<div className="flex flex-col gap-4">
<div className="flex flex-col gap-3">
<Label htmlFor="title">Title</Label>
<Input id="title" value="Sample Title" className="col-span-3" />
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="description">Description</Label>
<Input
id="description"
value="Sample Description"
className="col-span-3"
/>
</div>
</div>
</div>
<SheetFooter>
<Button type="submit">Save changes</Button>
<SheetClose render={<Button variant="outline">Close</Button>} />
</SheetFooter>
</SheetContent>
</Sheet>
);
}
Installation
npx shadcn@latest add "https://eo-n.vercel.app/r/sheet"
Usage
Import all parts and piece them together.
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet";
<Sheet>
<SheetTrigger>Open</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Are you sure you want to proceed?</SheetTitle>
<SheetDescription>
This action may have permanent effects. Please confirm if you want to
continue.
</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>
Examples
Side
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet";
export function SheetSide() {
return (
<Sheet>
<SheetTrigger render={<Button variant="outline">Open</Button>} />
<SheetContent side="bottom" hideCloseIcon>
<SheetHeader>
<SheetTitle>Edit profile</SheetTitle>
<SheetDescription>
Update the details below and click save to apply changes.
</SheetDescription>
</SheetHeader>
<div className="flex flex-col gap-4 px-4">
<div className="flex flex-col gap-3">
<Label htmlFor="title">Title</Label>
<Input id="title" value="Sample Title" className="col-span-3" />
</div>
<div className="flex flex-col gap-3">
<Label htmlFor="description">Description</Label>
<Input
id="description"
value="Sample Description"
className="col-span-3"
/>
</div>
</div>
<SheetFooter className="group-data-[side=bottom]:flex-row-reverse group-data-[side=top]:flex-row-reverse">
<Button type="submit">Save changes</Button>
<SheetClose render={<Button variant="outline">Close</Button>} />
</SheetFooter>
</SheetContent>
</Sheet>
);
}
Open On Menu
In order to open a sheet using a menu, control the sheet state and open it imperatively using the onClick
handler on the menu item.
Return Focus Properly
Make sure to also use the sheet’s finalFocus
prop to return focus back
to the menu trigger.
import * as React from "react";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuPositioner,
DropdownMenuTrigger,
} from "../ui/dropdown-menu";
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "../ui/sheet";
export default function DropdownMenuRadio() {
const menuTriggerRef = React.useRef<HTMLButtonElement>(null);
const [sheetOpen, setSheetOpen] = React.useState(false);
return (
<React.Fragment>
<DropdownMenu>
{/* Set the trigger ref */}
<DropdownMenuTrigger ref={menuTriggerRef}>Open</DropdownMenuTrigger>
<DropdownMenuPositioner>
<DropdownMenuContent>
{/* Open the sheet when the menu item is clicked */}
<DropdownMenuItem onClick={() => setSheetOpen(true)}>
Open sheet
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenuPositioner>
</DropdownMenu>
{/* Control the sheet state */}
<Sheet open={sheetOpen} onOpenChange={setSheetOpen}>
{/* Return focus to the menu trigger when the sheet is closed */}
<SheetContent finalFocus={menuTriggerRef}>
<SheetHeader>
<SheetTitle>Are you sure you want to proceed?</SheetTitle>
<SheetDescription>
This action may have permanent effects. Please confirm if you want
to continue.
</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>
</React.Fragment>
);
}
API Reference
Content
Contains content to be rendered in the open sheet.
Prop | Type | Default |
---|---|---|
hideCloseIcon? | boolean | false |
side | "top" | "right" | "bottom" | "left" | right |