Skip to main content

Custom gestures do not conflict with system gestures

ab-001958 · mobile-ux-patterns.touch-gestures.gesture-conflicts
Severity: highactive

Why it matters

A PanGestureHandler wired to the root view or main screen swallows the iOS edge-swipe-back gesture — users can no longer navigate back and file crash-level bug reports. Globally-scoped swipe handlers also fight with ScrollView momentum, producing frozen scrolls and ghost taps. Apple's HIG explicitly reserves edge gestures for the system, and conflicts here are a common rejection reason during App Store review.

Severity rationale

High because breaking system navigation gestures strands users on a screen with no visible way out.

Remediation

Scope every custom gesture to the smallest possible subtree and never attach a pan handler at the screen or NavigationContainer level. Use react-native-gesture-handler's simultaneousHandlers and waitFor to coordinate with scroll gestures:

<PanGestureHandler onGestureEvent={onSwipe} activeOffsetX={[-20, 20]}>
  <Animated.View style={animatedStyle}>{/* card only */}</Animated.View>
</PanGestureHandler>

Set activeOffsetX so horizontal swipes on the edge still reach the native navigator.

Detection

  • ID: mobile-ux-patterns.touch-gestures.gesture-conflicts

  • Severity: high

  • What to look for: List all custom gesture handlers in the app (PanGestureHandler, SwipeGestureHandler, PinchGestureHandler, etc.). For each, check whether it is scoped to a specific component or applied globally. Check for conflicts with iOS swipe-back, Android back button, and scroll gestures.

  • Pass criteria: All custom gestures are scoped to specific components (not applied at root or screen level) and do not interfere with at least 3 system gestures: iOS swipe-back navigation, Android back button, and scroll gestures. Report the count even on pass: "Found N custom gesture handlers, all scoped correctly."

  • Fail criteria: Any custom gesture is globally applied or conflicts with system navigation (e.g., custom pan handler on main screen prevents swipe-back on iOS, swipe handler interferes with scrolling).

  • Skip (N/A) when: The app uses no custom gestures (only standard buttons and taps) — no react-native-gesture-handler or manual gesture code detected.

  • Detail on fail: Identify the gesture conflict. Quote the handler component and its scope. Example: "Pan gesture on main screen prevents iOS swipe-back navigation on all screens." or "Custom swipe-to-delete on list items interferes with horizontal scroll in some cases."

  • Remediation: Use react-native-gesture-handler with proper gesture configuration to avoid conflicts. Scope gestures to specific components and use simultaneous handlers carefully:

    import { GestureHandlerRootView, PanGestureHandler } from 'react-native-gesture-handler';
    
    // Scope gesture to specific component, not whole screen
    <GestureHandlerRootView>
      <PanGestureHandler onGestureEvent={onSwipe}>
        <Animated.View style={animatedStyle}>
          {/* Swipeable card */}
        </Animated.View>
      </PanGestureHandler>
    </GestureHandlerRootView>
    

    Use simultaneousHandlers or waitFor to coordinate multiple gestures and prevent conflicts with built-in scroll and navigation gestures.

Taxons

History