Star on GitHub
npm install react-driftkit
Edge
Snap Point
Close on Outside Click
on
DraggableSheetDrag the handle to resize between snap points. Flick fast to skip stops. Tap the × to close.
Prop Type Default
children
Content rendered inside the sheet.
ReactNode
edge
Edge the sheet is pinned to.
'bottom' | 'top' | 'left' | 'right' 'bottom'
snapPoints
Ordered list of stops. Mix presets ('peek', 'half', 'full', 'closed'), raw pixel numbers, and percentage strings like '40%'.
SnapPoint[] ['peek', 'half', 'full']
defaultSnap
Uncontrolled initial stop.
SnapPoint middle of snapPoints
snap
Controlled current stop. When set, parent drives transitions.
SnapPoint
onSnapChange
Fires on drag release with the resolved stop and its pixel size.
(snap: SnapPoint, sizePx: number) => void
draggable
Whether the user can drag the sheet.
boolean true
dragHandleSelector
CSS selector for a nested handle. When set, drag only begins inside matching elements.
string
velocityThreshold
Flick velocity (px/ms) above which a release advances one stop in the flick direction.
number 0.5
closeOnOutsideClick
When true, a pointerdown outside the sheet collapses it to 0 and fires onSnapChange('closed', 0). Ignored while already closed or mid-drag.
boolean false
style
Additional inline styles for the wrapper.
CSSProperties {}
className
Additional CSS class for the wrapper.
string ''

The wrapper exposes data-edge, data-snap, and data-dragging so you can drive styles from CSS without re-rendering.

tsx
import { DraggableSheet } from 'react-driftkit';

function App() {
  return (
    <DraggableSheet snapPoints={['peek', 'half', 'full']} defaultSnap="half">
      <div className="my-sheet">
        <div data-handle className="sheet-handle" />
        <div className="sheet-body">Details, filters, cart...</div>
      </div>
    </DraggableSheet>
  );
}
typescript
type SheetEdge = 'bottom' | 'top' | 'left' | 'right';
type SnapPoint =
  | 'closed'
  | 'peek'
  | 'half'
  | 'full'
  | number
  | `${number}%`;

interface DraggableSheetProps {
  children: ReactNode;
  edge?: SheetEdge;
  snapPoints?: SnapPoint[];
  defaultSnap?: SnapPoint;
  snap?: SnapPoint;
  onSnapChange?: (snap: SnapPoint, sizePx: number) => void;
  draggable?: boolean;
  dragHandleSelector?: string;
  velocityThreshold?: number;
  closeOnOutsideClick?: boolean;
  style?: CSSProperties;
  className?: string;
}

Enjoying react-driftkit?

Star the repo on GitHub to help more devs discover it.

Star on GitHub