Reference

Sheet API

The sheet API is assembled from state, view, content, and action primitives so consumers can adopt only the layers they need.

View as Markdown

The headless Sheet contract is a compound React API. Every primitive forwards its ref and normal DOM props unless the table says otherwise.

Import

tsx
import {
  Sheet,
  SheetStack,
} from "velvet-ui/sheet";
import "velvet-ui/sheet.css";

Sheet.Root

PropTypeDefaultPurpose
openbooleanuncontrolledControlled presented state
defaultOpenbooleanfalseInitial uncontrolled state
onOpenChange(open) => voidReceives requested state changes
snapnumberuncontrolledControlled detent index
defaultSnapnumberdefaultOpen ? 1 : 0Initial detent
onSnapChange(snap) => voidReceives detent changes
sheetRole"dialog" | "alertdialog""dialog"Modal semantics and dismissal policy
licensestringReserved package license value

Sheet.Panel

Panel is the convenient composition of Portal, View, Backdrop, Content, and an optional Handle.

PropTypeDefault
sideSheetSidebottom
snapPointsdetent or arraynone
modal, dismissible, draggablebooleanView defaults
portalbooleantrue
containerElement or DocumentFragmentdocument.body
portalProps, viewPropspart props
backdropboolean or elementtrue
backdropPropsBackdrop props
handleboolean or elementtrue
handlePropsHandle props
contentPropsContent props
travelAnimation, stackingAnimationanimation map
tsx
<Sheet.Root>
  <Sheet.Trigger>Open filters</Sheet.Trigger>
  <Sheet.Panel
    side="bottom"
    snapPoints={["40lvh", "78lvh"]}
    viewProps={{ tracks: "auto", nativeEdgeSwipePrevention: true }}
    backdropProps={{ travelAnimation: { opacity: [0, 0.42] } }}
  >
    <Sheet.Title>Filters</Sheet.Title>
    <Filters />
    <Sheet.Close>Apply</Sheet.Close>
  </Sheet.Panel>
</Sheet.Root>

Sheet.View

PropTypeDefaultPurpose
sidetop | right | bottom | left | centerbottomAuthored content placement
snapPointsnumber | string | arraynoneIntermediate resting lengths
draggablebooleantrueEnables native gesture travel
dismissiblebooleantrueAllows the closed destination
modalbooleantrueEnables inertness, focus scope, and scroll lock
tracksTrack | Track[] | "auto"inferredAllowed gesture direction or scroll handoff
swipeOvershootbooleantrueAllows native rubber-band travel
swipeTrapboolean | stringunsetContains overscroll at the sheet boundary
snapOutAcceleration"auto" | numberautoBiases native travel toward dismissal
snapToEndDetentsAcceleration"auto" | numberautoBiases travel toward edge detents
enteringAnimationSettingspreset or settingssmoothProgrammatic opening motion
exitingAnimationSettingspreset or settings520 / 44 / 1 springProgrammatic closing motion
steppingAnimationSettingspreset or settingsentering settingsProgrammatic detent motion
nativeEdgeSwipePreventionbooleanfalsePrevents browser edge navigation conflicts

View callbacks

CallbackPayload
onTravel{ progress, range, progressAtDetents }
onTravelStartno payload
onTravelEndno payload
onTravelStatusChangeidleOutside, entering, idleInside, stepping, exiting
onClickOutsideobject or handler with changeDefault
onEscapeKeyDownobject or handler with changeDefault
tsx
<Sheet.View
  onClickOutside={{ dismiss: false }}
  onEscapeKeyDown={({ changeDefault }) => {
    if (formState.isDirty) changeDefault({ dismiss: false });
  }}
/>

Visual and action parts

PartImportant props
Sheet.Portalcontainer
Sheet.Backdropswipeable, travelAnimation, asChild
Sheet.ContenttravelAnimation, stackingAnimation, asChild
Sheet.BleedingBackgroundnormal div props, asChild
Sheet.Outlettravel and stacking animation
Sheet.Triggeraction, snapTo, onPress, asChild
Sheet.CloseTrigger fixed to close intent
Sheet.StepsnapTo, direction: up | down
Sheet.Handleclose or step action
Sheet.Titleheading props; supplies accessible name
Sheet.Descriptionparagraph props; supplies description

Actions and detent indexes

0 means closed. Positive indexes address resting detents in travel order. Use action="open", close, toggle, step, or { type: 'step', snapTo, direction }.

tsx
<Sheet.Trigger action="open">Open</Sheet.Trigger>
<Sheet.Trigger action="toggle">Toggle</Sheet.Trigger>
<Sheet.Step snapTo={2}>Details</Sheet.Step>
<Sheet.Handle action={{ type: "step", direction: "down" }} />

asChild contract

The child becomes the real DOM node. It must accept the forwarded ref, className, style, ARIA attributes, disabled state, and event handlers.

If a design-system Button merges handlers, call both handlers unless the consumer event is already prevented. Dropping Velvet’s handler makes the control look enabled while doing nothing.