Sheet
An edge-positioned panel that slides in from the side of the screen, built on the Base UI Dialog primitive.
"use client";
import { Button } from "@/registry/base/ui/button";
import { Input } from "@/registry/base/ui/input";
import { Label } from "@/registry/base/ui/label";
import {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@/registry/base/ui/sheet";
export default function SheetDemo() {
return (
<Sheet>
<SheetTrigger render={<Button variant="outline">Open sheet</Button>} />
<SheetContent>
<SheetHeader>
<SheetTitle>Edit profile</SheetTitle>
<SheetDescription>
Make changes to your profile here. Click save when you're
done.
</SheetDescription>
</SheetHeader>
<div className="grid flex-1 auto-rows-min gap-6 px-4">
<div className="grid gap-2">
<Label htmlFor="sheet-name">Name</Label>
<Input id="sheet-name" defaultValue="Pedro Duarte" />
</div>
<div className="grid gap-2">
<Label htmlFor="sheet-username">Username</Label>
<Input id="sheet-username" defaultValue="@peduarte" />
</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://sevenui.dev/r/sheet.jsonUsage
"use client";
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 default function SheetDemo() {
return (
<Sheet>
<SheetTrigger render={<Button variant="outline">Open sheet</Button>} />
<SheetContent>
<SheetHeader>
<SheetTitle>Edit profile</SheetTitle>
<SheetDescription>
Make changes to your profile here. Click save when you're done.
</SheetDescription>
</SheetHeader>
<div className="grid flex-1 auto-rows-min gap-6 px-4">
<div className="grid gap-2">
<Label htmlFor="sheet-name">Name</Label>
<Input id="sheet-name" defaultValue="Pedro Duarte" />
</div>
<div className="grid gap-2">
<Label htmlFor="sheet-username">Username</Label>
<Input id="sheet-username" defaultValue="@peduarte" />
</div>
</div>
<SheetFooter>
<Button type="submit">Save changes</Button>
<SheetClose render={<Button variant="outline">Close</Button>} />
</SheetFooter>
</SheetContent>
</Sheet>
);
}
Examples
Sides
"use client";
import { Button } from "@/registry/base/ui/button";
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@/registry/base/ui/sheet";
const sides = ["top", "right", "bottom", "left"] as const;
export default function SheetSide() {
return (
<div className="grid grid-cols-2 gap-2">
{sides.map((side) => (
<Sheet key={side}>
<SheetTrigger
render={
<Button variant="outline" className="capitalize">
{side}
</Button>
}
/>
<SheetContent side={side}>
<SheetHeader>
<SheetTitle className="capitalize">{side} sheet</SheetTitle>
<SheetDescription>
This panel slides in from the {side} edge of the screen.
</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>
))}
</div>
);
}
API reference
Sheet
Extends the Base UI Dialog Root — Sheet is a positioned Dialog rather than a distinct primitive. Per Base UI’s own guidance, an edge panel without swipe gestures is just a Dialog pinned to a screen edge; reach for Drawer when you need gesture-driven dragging.
| Prop | Type | Default |
|---|---|---|
open / defaultOpen |
boolean |
false |
onOpenChange |
(open: boolean) => void |
— |
modal |
true | false | "trap-focus" |
true |
disablePointerDismissal |
boolean |
false |
SheetContent
No Viewport part is used — the Popup is position: fixed against a
screen edge and slides via translate utilities, animated by
transition-transform.
| Prop | Type | Default |
|---|---|---|
side |
"top" | "right" | "bottom" | "left" |
"right" |
showCloseButton |
boolean — built-in ✕ |
true |
SheetTrigger, SheetClose, SheetHeader, SheetFooter, SheetTitle, SheetDescription, SheetOverlay, SheetPortal
Styled parts; trigger and close accept the render prop.