Stacksheetv1.1.4

Snap Points

Multi-stop bottom sheets that snap to predefined heights.

Overview

Bottom sheets can snap to predefined heights instead of only fully open or fully closed. This is useful for map overlays, media players, and any UI where the sheet should rest at intermediate positions.

Snap points only apply when side is "bottom".

const { StacksheetProvider, useSheet } = createStacksheet({
  side: "bottom",
  snapPoints: [0.25, 0.5, 1],
});

Snap point values

The SnapPoint type accepts three formats:

FormatExampleMeaning
Number 0–10.5Fraction of viewport height (50vh)
Number > 1300Pixel value (300px)
String"30rem"CSS length — supports px, rem, em, vh, %
// Mixed formats
createStacksheet({
  side: "bottom",
  snapPoints: [0.25, "400px", 1],
});

Points are resolved to pixels and sorted ascending at render time. Duplicates within 1px are removed.

Configuration

OptionTypeDefaultDescription
snapPointsSnapPoint[][]Snap positions (empty = no snapping)
snapPointIndexnumberControlled active snap index
onSnapPointChange(index: number) => voidCalled when the active snap point changes
snapToSequentialPointsbooleanfalsePrevent skipping intermediate snap points

Uncontrolled (default)

By default, the sheet opens at the last snap point (fully open) and manages its own snap state internally. The user can drag between snap points freely.

createStacksheet({
  side: "bottom",
  snapPoints: [0.3, 0.6, 1],
  onSnapPointChange: (index) => {
    console.log("Snapped to index:", index);
  },
});

Controlled

Pass snapPointIndex to control which snap point is active. Pair with onSnapPointChange to update your state.

const [snapIndex, setSnapIndex] = useState(2);

createStacksheet({
  side: "bottom",
  snapPoints: [0.25, 0.5, 1],
  snapPointIndex: snapIndex,
  onSnapPointChange: setSnapIndex,
});

Sequential snapping

By default, a fast swipe can skip intermediate snap points. Set snapToSequentialPoints: true to force the sheet to move one snap point at a time.

createStacksheet({
  side: "bottom",
  snapPoints: [0.25, 0.5, 0.75, 1],
  snapToSequentialPoints: true,
});

Dismissal

When the user drags past the smallest snap point, the sheet dismisses entirely. The velocity and direction of the gesture determine whether it snaps or dismisses — a fast downward swipe past the bottom snap point will close the sheet.

To prevent dismissal entirely, set dismissible: false. The sheet will snap to the smallest point instead of closing.

Interaction with drag

Snap points use the same gesture pipeline as regular drag-to-dismiss. The drag thresholds (closeThreshold, velocityThreshold) are ignored when snap points are active — the snap point algorithm handles release targeting instead.

Drag handles (data-stacksheet-handle) and no-drag zones (data-stacksheet-no-drag) work the same way.

On this page