Skip to content

BottomSheet: evaluate adopting @gorhom/bottom-sheet to replace bespoke gesture implementation #1183

@georgewrmarshall

Description

@georgewrmarshall

Background

PR #1165 migrated BottomSheetDialog from the RNGH v1 PanGestureHandler / useAnimatedGestureHandler API to the RNGH v2 GestureDetector / Gesture.Pan() API, required by the upgrade to react-native-reanimated ~4.1.1 and react-native-gesture-handler ~2.28.0.

As part of that migration, panGestureHandlerProps was removed as a breaking change. It was a passthrough shim that gave consumers access to the full PanGestureHandler configuration surface — things like simultaneousHandlers, activeOffsetY, failOffsetX, hitSlop, minDist. The prop was never called in MetaMask Mobile or Extension consumer code, and the simultaneousHandlers use case (the only real one in the codebase) was already silently broken because applyPanGestureProps never mapped it to gesture.simultaneousWithExternalGesture().

See MIGRATION.md for the breaking change documentation.

The problem this creates

Without panGestureHandlerProps, consumers have no escape hatch to configure the underlying pan gesture. The most immediately impacted case is scrollable content inside a BottomSheet on Android — without gesture coordination, the bottom sheet's pan gesture intercepts scroll attempts and dismisses the sheet instead of scrolling the list.

The ScrollableList Storybook story demonstrates this: it still passes a ref to the ScrollView but that ref is now disconnected — there is nothing coordinating the scroll and dismiss gestures.

Options explored

Option A: Expose individual first-class props

Add explicit props for common configurations (activeOffsetY, simultaneousWithRef, etc.). Clean public API but the component becomes the gatekeeper — if a consumer needs something not exposed, they're stuck.

Option B: gestureModifier callback

Give consumers a function that receives the base Gesture.Pan() object and returns it configured:

<BottomSheet
  gestureModifier={(gesture) =>
    gesture
      .activeOffsetY([-5, 5])
      .simultaneousWithExternalGesture(scrollRef)
  }
>

This is the v2-idiomatic equivalent of panGestureHandlerProps — same full-surface access, type-safe, consumer owns any configuration layered on top of the component's core behaviour. The component creates the base gesture with its internal onStart/onUpdate/onEnd logic and passes it to the modifier before using it.

Option C: Adopt @gorhom/bottom-sheet ← preferred direction

Replace the bespoke gesture management entirely. @gorhom/bottom-sheet v5 handles simultaneous gesture coordination with scroll views, keyboard avoidance, and sheet snapping as first-class concerns. The consumer never needs to think about gesture configuration.

@gorhom/bottom-sheet is already present as a devDependency in apps/storybook-react-native. The current BottomSheetDialog implementation is ~300 lines managing concerns that @gorhom/bottom-sheet handles out of the box.

Primary goal: verify compatibility with MetaMask Mobile

Before committing to Option C, confirm that @gorhom/bottom-sheet v5 is compatible with the MetaMask Mobile stack:

  • Check if MetaMask Mobile already uses @gorhom/bottom-sheet anywhere — if so, which version
  • Verify peer dependency compatibility: @gorhom/bottom-sheet v5 requires react-native-reanimated >= 3 and react-native-gesture-handler >= 2 (both satisfied on our current stack)
  • Audit the BottomSheet / BottomSheetDialog public API surface against @gorhom/bottom-sheet's API — identify what maps cleanly and what would be a breaking change for consumers
  • Check if MetaMask Mobile uses BottomSheet from this design system or its own copy in app/component-library/

Intermediate path (if Option C is blocked)

If @gorhom/bottom-sheet adoption needs more time, implement Option B (gestureModifier callback) as a non-breaking addition to restore the escape hatch:

export type BottomSheetDialogProps = {
  // ...existing props
  gestureModifier?: (
    gesture: ReturnType<typeof Gesture.Pan>,
  ) => ReturnType<typeof Gesture.Pan>;
};

This unblocks the simultaneousHandlers scroll use case without re-introducing the v1 prop surface.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions