Sheet
A Drawer-adjacent panel that slides in from the top or bottom edge with iOS-style snap points. Drag the handle to rest at configured heights, or flick past the smallest snap to dismiss. Modal by default — it traps focus and locks page scroll.
Features
Slides from the top or bottom edge via the
side prop.Snap points let the sheet rest at multiple heights.
Drag the handle to resize, or past the smallest snap to dismiss.
Closes on Escape and overlay click when dismissible.
Portal rendering with focus trap and scroll lock when modal.
Can be controlled or uncontrolled.
Example
Anatomy
import { Sheet } from '@wire-ui/react'
<Sheet.Root snapPoints={[0.4]}>
<Sheet.Trigger>Open Sheet</Sheet.Trigger>
<Sheet.Portal>
<Sheet.Overlay />
<Sheet.Content>
<Sheet.Handle />
<Sheet.Title>Bottom sheet</Sheet.Title>
<Sheet.Description>Slides up from the bottom edge.</Sheet.Description>
<Sheet.Close>Done</Sheet.Close>
</Sheet.Content>
</Sheet.Portal>
</Sheet.Root>Styling
Sheet sets data-state on Overlay and Content, plus data-side and data-dragging on Content. Use them to drive slide-in transitions and to disable the transition while dragging.
<Sheet.Overlay className="
bg-black/50
data-[state=closed]:opacity-0
transition-opacity
" />
<Sheet.Content className="
transition-transform
data-[side=top]:rounded-b-[20px]
data-[side=bottom]:rounded-t-[20px]
data-[dragging]:transition-none
" />Using data attributes
Overlay receives data-state; Content receives data-state, data-side, and (while dragging) data-dragging.
/* Slide up from bottom */
[data-side="bottom"][data-state="closed"] { transform: translateY(100%); }
[data-side="bottom"][data-state="open"] { transform: translateY(0); }
/* Kill the transition mid-drag so the handle tracks the pointer */
[data-dragging] { transition: none; }Root props
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled open state |
defaultOpen | boolean | false | Initial open state (uncontrolled) |
onOpenChange | (open: boolean) => void | — | Called when the open state changes |
side | 'top' | 'bottom' | 'bottom' | Edge the sheet slides from |
snapPoints | number[] | [1] | Rest positions. Values ≤ 1 are a fraction of the viewport; values > 1 are px. Order smallest → largest |
activeSnapPoint | number | — | Controlled active snap index |
defaultActiveSnapPoint | number | largest snap | Initial active snap index |
onActiveSnapPointChange | (index: number) => void | — | Called when the active snap index changes |
modal | boolean | true | Render a focus-trapping, scroll-locking modal |
dismissible | boolean | true | Allow closing by dragging past the smallest snap, Escape, or overlay click |
Trigger / Portal / Overlay / Handle / Title / Description / Close props
| Sub-component | Type | Description |
|---|---|---|
Sheet.Trigger | ButtonHTMLAttributes | Opens the sheet on click. Sets aria-haspopup="dialog" and aria-expanded |
Sheet.Portal | { container?: Element | null } | Renders children into container (defaults to document.body) when open |
Sheet.Overlay | HTMLAttributes | Backdrop. Closes the sheet on click when dismissible |
Sheet.Content | HTMLAttributes | The panel; role="dialog", aria-modal, labelled/described by Title/Description |
Sheet.Handle | HTMLAttributes | Drag affordance; role="button", aria-label="Drag to resize" |
Sheet.Title | HTMLAttributes | Renders an <h2> referenced by aria-labelledby |
Sheet.Description | HTMLAttributes | Renders a <p> referenced by aria-describedby |
Sheet.Close | ButtonHTMLAttributes | Closes the sheet on click |
Data attributes
| Attribute | Element | Values |
|---|---|---|
data-state | Overlay, Content | "open" / "closed" |
data-side | Content | "top" / "bottom" |
data-dragging | Content | Present while the handle is being dragged |
Accessibility
Sheet.Contentrendersrole="dialog"witharia-modaland is labelled bySheet.Title(aria-labelledby) and described bySheet.Description(aria-describedby).- When
modalis set, focus is trapped inside the content and page scroll is locked. Sheet.Triggerexposesaria-haspopup="dialog"and reflects open state viaaria-expanded.
Keyboard Interactions
| Key | Description |
|---|---|
| Escape | Closes the sheet when dismissible. |
| Tab | Moves focus to the next focusable element inside the sheet. |
| Shift+Tab | Moves focus to the previous focusable element inside the sheet. |
Last updated on