Gestures
react-edge-sheet supports touch and mouse drag gestures for dismissing sheets and snapping between sizes.
Drag to Dismiss
Add draggable to enable the drag-to-dismiss gesture. The demo below uses showDragHandle — grab the pill and drag down:
<Sheet ref={ref} edge="bottom" draggable>
<div style={{ padding: '2rem' }}>
<p>Drag down to close</p>
</div>
</Sheet>Works on all edges — drag down for bottom, drag up for top, drag left for left, drag right for right.
Drag Handle
Add a visible handle pill with showDragHandle. This also enables draggable automatically:
<Sheet ref={ref} edge="bottom" showDragHandle>
<div style={{ padding: '2.5rem 2rem 2rem' }}>
<p>Content here</p>
</div>
</Sheet>The handle is positioned relative to the edge:
bottom→ top-center, horizontal pilltop→ bottom-center, horizontal pillleft→ right-center, vertical pillright→ left-center, vertical pill
To show the handle without enabling drag:
<Sheet ref={ref} edge="bottom" showDragHandle draggable={false}>
...
</Sheet>Drag Handle Customization
Style the default pill with dragHandleStyle / dragHandleClassName:
<Sheet
ref={ref}
edge="bottom"
showDragHandle
dragHandleStyle={{ background: 'rgba(255,255,255,0.6)', width: '3rem' }}
>
...
</Sheet>Replace it entirely with dragHandleComponent. showDragHandle is not required — providing dragHandleComponent is enough to render it:
<Sheet
ref={ref}
edge="bottom"
dragHandleComponent={
<div style={{
position: 'absolute',
top: '0.75rem',
left: '50%',
transform: 'translateX(-50%)',
width: '2rem',
height: '0.2rem',
borderRadius: 999,
background: 'white',
}} />
}
>
...
</Sheet>When dragHandleComponent is set, dragHandleStyle and dragHandleClassName are ignored.
Drag Thresholds
Control when a release triggers dismiss:
<Sheet
ref={ref}
edge="bottom"
draggable
dragThreshold={120} // px dragged (default: 80)
dragVelocityThreshold={0.5} // px/ms velocity (default: 0.3)
>
...
</Sheet>A release triggers dismiss if either condition is met:
|dragOffset| > dragThresholdvelocity > dragVelocityThreshold
For a forgiving feel (easier to dismiss), lower both values. For a sticky feel (harder to dismiss), raise them.
Rubber Band
Dragging against the dismiss direction (e.g. dragging up on a bottom sheet) creates a rubber band resistance — the offset is 20% of actual drag distance. This gives natural physical feedback.
Snap Points
Use snapPoints to define multiple heights (or widths for left/right edges). The demo below has three snap heights — drag up/down to cycle between them:
<Sheet
ref={ref}
edge="bottom"
showDragHandle
snapPoints={['200px', '50vh', '90vh']}
>
<div style={{ padding: '2rem' }}>
<p>Drag to snap between heights</p>
</div>
</Sheet>Snap points should be in ascending order (smallest to largest).
Default Snap Point
By default the sheet opens at the largest snap point (last index). Override with defaultSnapPoint:
<Sheet
ref={ref}
edge="bottom"
showDragHandle
snapPoints={['25vh', '50vh', '90vh']}
defaultSnapPoint={1} // opens at 50vh
>
...
</Sheet>onSnapChange
React to snap changes with onSnapChange:
<Sheet
ref={ref}
edge="bottom"
showDragHandle
snapPoints={['200px', '50vh', '90vh']}
onSnapChange={(index) => console.log('snapped to', index)}
>
...
</Sheet>Collapsing from the smallest snap
Dragging toward dismiss from the smallest snap point (index === 0) closes the sheet entirely.
Common Patterns
Mini / Half / Full Sheet
<Sheet
ref={ref}
edge="bottom"
showDragHandle
snapPoints={['25vh', '50vh', '92vh']}
style={{ background: 'white', borderRadius: '1.5rem 1.5rem 0 0' }}
>
<div style={{ padding: '1rem 1.5rem 2rem' }}>
<h3>Title</h3>
<p>Your content here.</p>
</div>
</Sheet>Map-Style Sheet
<Sheet
ref={ref}
edge="bottom"
showDragHandle
snapPoints={['120px', '45vh', '85vh']}
defaultSnapPoint={0}
style={{ background: 'white', borderRadius: '1.5rem 1.5rem 0 0' }}
>
<div style={{ padding: '1.5rem' }}>
<h3>Nearby Places</h3>
{/* list items */}
</div>
</Sheet>Music Player Snap
Drag up to expand to full player, drag down to collapse to mini player. Drag below mini to close.
<Sheet
ref={ref}
edge="bottom"
showDragHandle
snapPoints={['80px', '100vh']}
defaultSnapPoint={0}
style={{ background: '#1a1a1a', borderRadius: '1.5rem 1.5rem 0 0' }}
>
<div style={{ padding: '1rem 1.5rem' }}>
{/* mini player or full player depending on snap */}
</div>
</Sheet>Sidebar with Drag
<Sheet
ref={ref}
edge="left"
draggable
maxWidth="320px"
style={{ background: 'white', height: '100%' }}
>
<nav style={{ padding: '2rem' }}>
{/* navigation items */}
</nav>
</Sheet>