Sheet
Sliding panel for dialogs, forms, and multi-step flows. Built on Base UI Dialog with motion-powered animations.
Overview
The Sheet component presents content in a panel that slides from any edge of the viewport. It's ideal for lightweight flows such as settings, filters, or multi-step forms. Built on Base UI Dialog primitives with Framer Motion for smooth, customizable animations.
Usage
import {
Sheet,
SheetTrigger,
SheetContent,
SheetHeader,
SheetBody,
SheetFooter,
SheetTitle,
SheetDescription,
SheetClose,
} from "@tilt-legal/cubitt-components/primitives";<Sheet>
<SheetTrigger render={<Button />}>Open Sheet</SheetTrigger>
<SheetContent side="right">
<SheetHeader>
<SheetTitle>Sheet Title</SheetTitle>
<SheetDescription>Sheet description goes here.</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>Using Cubitt's URL-state hooks, you can sync the sheet state with the URL by providing a paramName:
// Opens when ?settings=true in URL
<Sheet paramName="settings">
<SheetTrigger render={<Button />}>Open Settings</SheetTrigger>
<SheetContent side="right">
<SheetHeader>
<SheetTitle>Settings</SheetTitle>
<SheetDescription>
Configure your preferences.
</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>
// Advanced options:
<Sheet
paramName="sheet"
paramClearOnDefault={true} // Remove param when closed
onUrlValueChange={(value) => console.log('Sheet open:', value)}
>
{/* ... */}
</Sheet>Examples
Basic
With Actions
With Form
Different Sides
Sheets can slide in from any edge of the viewport.
// Left side
<Sheet>
<SheetTrigger render={<Button variant="secondary" />}>Left</SheetTrigger>
<SheetContent side="left">
<SheetHeader>
<SheetTitle>Left Side</SheetTitle>
<SheetDescription>This sheet slides in from the left.</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>
// Right side (default)
<Sheet>
<SheetTrigger render={<Button variant="secondary" />}>Right</SheetTrigger>
<SheetContent side="right">
<SheetHeader>
<SheetTitle>Right Side</SheetTitle>
<SheetDescription>This sheet slides in from the right.</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>
// Top side
<Sheet>
<SheetTrigger render={<Button variant="secondary" />}>Top</SheetTrigger>
<SheetContent side="top">
<SheetHeader>
<SheetTitle>Top Side</SheetTitle>
<SheetDescription>This sheet slides in from the top.</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>
// Bottom side
<Sheet>
<SheetTrigger render={<Button variant="secondary" />}>Bottom</SheetTrigger>
<SheetContent side="bottom">
<SheetHeader>
<SheetTitle>Bottom Side</SheetTitle>
<SheetDescription>This sheet slides in from the bottom.</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>Floating Sheet
Scrollable Content
Sheet with long content that scrolls. The header and footer remain sticky with a blurred background effect.
<Sheet>
<SheetTrigger render={<Button variant="secondary" />}>
Terms & Conditions
</SheetTrigger>
<SheetContent side="right">
<SheetHeader>
<SheetTitle>Terms and Conditions</SheetTitle>
<SheetDescription>
Please read and accept our terms and conditions.
</SheetDescription>
</SheetHeader>
<SheetBody className="space-y-4 text-sm text-fg-2">
{/* Long content... */}
</SheetBody>
<SheetFooter>
<SheetClose render={<Button variant="secondary" />}>Decline</SheetClose>
<Button>Accept</Button>
</SheetFooter>
</SheetContent>
</Sheet>Without Close Button
URL State
Sheet with URL state synchronization for shareable sheet states.
import {
Button,
Sheet,
SheetTrigger,
SheetContent,
SheetHeader,
SheetBody,
SheetTitle,
SheetDescription,
SheetFooter,
SheetClose,
} from "@tilt-legal/cubitt-components/primitives";
// Sheet state synced with ?settings=true
<Sheet paramName="settings" defaultOpen={false}>
<SheetTrigger render={<Button variant="secondary" />}>
Open with URL state
</SheetTrigger>
<SheetContent side="right">
<SheetHeader>
<SheetTitle>Settings</SheetTitle>
<SheetDescription>
This sheet's state is synced with the URL. Check the URL parameter when
you open it!
</SheetDescription>
</SheetHeader>
<SheetFooter>
<SheetClose render={<Button variant="secondary" />}>Cancel</SheetClose>
<Button>Save</Button>
</SheetFooter>
</SheetContent>
</Sheet>;API Reference
Sheet
Root component that manages sheet state.
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | - | Controlled open state of the sheet. |
defaultOpen | boolean | false | Default open state for uncontrolled usage. |
onOpenChange | (open: boolean) => void | - | Callback fired when the open state changes. |
modal | boolean | true | Whether the sheet is modal (locks scroll). |
URL State Props
The following props enable URL state management by syncing the sheet open/closed state with URL parameters via TanStack Router search params. When paramName is provided, the sheet's state will be reflected in the URL.
| Prop | Type | Default | Description |
|---|---|---|---|
paramName | string | - | URL parameter name for syncing state with URL. When provided, enables URL state management. |
paramMatchValue | string | - | Value that must match for the sheet to open. |
onUrlValueChange | (value: boolean | null) => void | - | Callback when URL parameter value changes. |
paramClearOnDefault | boolean | true | Remove URL param when value equals default. |
paramThrottle | number | - | Throttle URL updates in milliseconds. |
paramDebounce | number | - | Debounce URL updates in milliseconds. |
SheetTrigger
Button that opens the sheet.
| Prop | Type | Default | Description |
|---|---|---|---|
render | React.ReactElement | - | Custom trigger element to render. |
SheetContent
Container for the sheet content with backdrop and animations.
| Prop | Type | Default | Description |
|---|---|---|---|
side | 'top' | 'right' | 'bottom' | 'left' | 'right' | Which edge the sheet slides from. |
float | boolean | false | Renders content as a floating card with rounded corners and border. |
showCloseButton | boolean | true | Show a built-in close button in the corner. |
className | string | - | Additional CSS classes for the sheet popup. |
SheetHeader / SheetFooter
Container components for sheet header and footer with sticky positioning.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes for the header. |
SheetBody
Container for the main content area with consistent padding.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes for the body. |
SheetTitle
The accessible title of the sheet.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes for the title. |
SheetDescription
Description text that provides context about the sheet.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes for the description. |
SheetClose
Button that closes the sheet.
| Prop | Type | Default | Description |
|---|---|---|---|
render | React.ReactElement | - | Custom close button element to render. |
className | string | - | Additional CSS classes for the close button. |