Sheet
A slide-out panel component that appears from any edge of the screen with size options and slot composition.
Basic
A slide-out panel that appears from any edge of the screen. Built on Radix UI with smooth CSS animations, focus trap, and slot-based composition.
Installation
Install the component via the CLI in one command.
npx @work-rjkashyap/unified-ui add sheetpnpm dlx @work-rjkashyap/unified-ui add sheetnpx @work-rjkashyap/unified-ui add sheetbunx @work-rjkashyap/unified-ui add sheetIf you haven't initialized your project yet, run npx @work-rjkashyap/unified-ui init first. See the CLI docs for details.
Or install the full package
Use this approach if you prefer to install the entire design system as a dependency instead of copying individual components.
npm install @work-rjkashyap/unified-uipnpm add @work-rjkashyap/unified-uiyarn add @work-rjkashyap/unified-uibun add @work-rjkashyap/unified-uiAnatomy
import {
Sheet,
SheetTrigger,
SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription,
SheetClose,
Button,
Input,
} from "@work-rjkashyap/unified-ui";Basic Usage
The Sheet uses a trigger-based pattern similar to Dialog. Wrap a button in SheetTrigger and the panel content in SheetContent. Radix UI handles open/close state, focus trapping, and scroll locking automatically.
<Sheet>
<SheetTrigger asChild>
<Button>Open Sheet</Button>
</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Panel Title</SheetTitle>
<SheetDescription>Optional description text.</SheetDescription>
</SheetHeader>
<div className="p-6">
<p>Sheet content goes here.</p>
</div>
<SheetFooter>
<SheetClose asChild>
<Button variant="secondary">Close</Button>
</SheetClose>
</SheetFooter>
</SheetContent>
</Sheet>Side
The side prop controls which edge of the screen the sheet slides in from. Four directions are supported.
| Side | Use Case |
|---|---|
right | Detail panels, settings, forms (default) |
left | Navigation drawers, sidebars |
top | Search bars, announcements, command palettes |
bottom | Action sheets, mobile menus |
Size
The size prop controls the width (for left/right sheets) or height (for top/bottom sheets) of the panel.
<SheetContent side="right" size="sm"> {/* 320px */}
<SheetContent side="right" size="md"> {/* 420px — default */}
<SheetContent side="right" size="lg"> {/* 560px */}
<SheetContent side="right" size="full"> {/* Full width/height */}| Size | Width (left/right) | Height (top/bottom) | Use Case |
|---|---|---|---|
sm | 320px | 320px | Compact panels, mobile nav |
md | 420px | 420px | Default forms and settings |
lg | 560px | 560px | Complex forms, data-heavy panels |
full | 100% | 100% | Full-screen overlays |
Slot Composition
Sheets use the same slot pattern as Dialog with SheetHeader, content area, and SheetFooter.
<SheetContent>
{/* Header — title, description, close button */}
<SheetHeader>
<SheetTitle>Panel Title</SheetTitle>
<SheetDescription>Description text</SheetDescription>
</SheetHeader>
{/* Body — your custom content (add your own padding) */}
<div className="flex-1 overflow-y-auto p-6">
<p>Scrollable content area</p>
</div>
{/* Footer — action buttons */}
<SheetFooter>
<SheetClose asChild>
<Button variant="secondary">Cancel</Button>
</SheetClose>
<Button variant="primary">Save</Button>
</SheetFooter>
</SheetContent>Navigation Drawer Pattern
A common pattern for mobile-style navigation sidebars.
<Sheet>
<SheetTrigger asChild>
<Button variant="ghost" iconOnly aria-label="Open menu">
<MenuIcon className="size-4" />
</Button>
</SheetTrigger>
<SheetContent side="left" size="sm">
<SheetHeader>
<SheetTitle>Navigation</SheetTitle>
</SheetHeader>
<nav className="flex flex-col gap-1 p-4">
<a href="/" className="px-3 py-2 text-sm rounded-md hover:bg-muted">
Home
</a>
<a
href="/docs"
className="px-3 py-2 text-sm rounded-md hover:bg-muted"
>
Documentation
</a>
<a
href="/components"
className="px-3 py-2 text-sm rounded-md hover:bg-muted"
>
Components
</a>
<a
href="/examples"
className="px-3 py-2 text-sm rounded-md hover:bg-muted"
>
Examples
</a>
</nav>
</SheetContent>
</Sheet>Settings Panel Pattern
A detail panel that slides in from the right with a form.
<Sheet>
<SheetTrigger asChild>
<Button variant="secondary" iconLeft={<SettingsIcon />}>
Settings
</Button>
</SheetTrigger>
<SheetContent side="right" size="md">
<SheetHeader>
<SheetTitle>Project Settings</SheetTitle>
<SheetDescription>
Update your project configuration. Changes are saved when you
click Save.
</SheetDescription>
</SheetHeader>
<div className="flex-1 overflow-y-auto p-6 flex flex-col gap-4">
<div className="flex flex-col gap-1.5">
<label className="text-sm font-medium">Project Name</label>
<Input placeholder="My Project" />
</div>
<div className="flex flex-col gap-1.5">
<label className="text-sm font-medium">Description</label>
<Textarea placeholder="What is this project about?" />
</div>
<div className="flex flex-col gap-1.5">
<label className="text-sm font-medium">Visibility</label>
<Select>
<SelectTrigger>
<SelectValue placeholder="Select visibility" />
</SelectTrigger>
<SelectContent>
<SelectItem value="public">Public</SelectItem>
<SelectItem value="private">Private</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<SheetFooter>
<SheetClose asChild>
<Button variant="secondary">Cancel</Button>
</SheetClose>
<Button variant="primary">Save Changes</Button>
</SheetFooter>
</SheetContent>
</Sheet>Controlled Mode
Use the open and onOpenChange props for programmatic control.
const [open, setOpen] = useState(false);
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger asChild>
<Button>Open</Button>
</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Controlled Sheet</SheetTitle>
</SheetHeader>
<div className="p-6">
<p>This sheet is controlled externally.</p>
<Button
variant="primary"
onClick={() => {
handleSave();
setOpen(false);
}}
>
Save & Close
</Button>
</div>
</SheetContent>
</Sheet>;Props
Sheet
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled open state. |
defaultOpen | boolean | — | Default open state (uncontrolled). |
onOpenChange | (open: boolean) => void | — | Callback when the open state changes. |
modal | boolean | true | Whether the sheet blocks interaction with the rest of the page. |
SheetContent
| Prop | Type | Default | Description |
|---|---|---|---|
side | "top" | "right" | "bottom" | "left" | "right" | Which edge the sheet slides in from. |
size | "sm" | "md" | "lg" | "full" | "md" | Width (left/right) or height (top/bottom) of the panel. |
className | string | — | Additional CSS classes. |
SheetHeader
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS classes. |
SheetFooter
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS classes. |
SheetTitle
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS classes. |
SheetDescription
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS classes. |
SheetTrigger
Uses Radix UI's DialogTrigger API. Use asChild to render the trigger as your own element.
SheetClose
Uses Radix UI's DialogClose API. Use asChild to render the close action as your own element.
Accessibility
Built on @radix-ui/react-dialog (the same primitive that powers the Dialog component) for full ARIA compliance.
- Focus trap — Focus is contained within the sheet when open (managed by Radix).
- Focus restoration — Focus returns to the trigger element when the sheet closes.
- Escape to close — Pressing
Escapecloses the sheet. - Click outside — Clicking the overlay backdrop closes the sheet.
- Scroll lock — Body scroll is locked while the sheet is open.
aria-labelledby— Automatically linked toSheetTitle.aria-describedby— Automatically linked toSheetDescription.- The close button has
aria-label="Close". - Uses
z-modalfor sheet content andz-overlayfor the backdrop. - Uses
rounded-lgper project guidelines for sheet panels. - Slide animations respect
prefers-reduced-motion.
Design Tokens
| Token | Usage |
|---|---|
--surface-raised | Sheet panel background |
--overlay | Backdrop overlay color |
--radius-lg | Sheet border radius (inner edge corners) |
--z-modal | Z-index for sheet content |
--z-overlay | Z-index for backdrop |
--shadow-lg | Sheet panel shadow |
--duration-normal | Slide animation timing |
--easing-standard | Slide animation easing |