# Custom gestures do not conflict with system gestures

- **Pattern:** `ab-001958` (`mobile-ux-patterns.touch-gestures.gesture-conflicts`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001958
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001958)

## 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:

```tsx
<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:** `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:

  ```tsx
  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: user-experience

HTML version: https://auditbuffet.com/patterns/ab-001958
