Description
When using a horizontal pan gesture for a carousel, releasing the finger after swiping triggers onPress events on underlying Pressable components, even when the pan gesture has been active and moved significantly. This does not happen with vertical scrolling (ScrollView/FlatList), which properly prevents click-through.
Environment
- React Native Gesture Handler version: 2.25.0
- React Native version: Latest (Expo SDK)
- Platform: Both iOS and Android
- Using: TypeScript, Expo Router, react-native-reanimated
Expected Behavior
When a pan gesture has been active and the user has swiped horizontally, releasing the finger should NOT trigger onPress events on underlying components, similar to how ScrollView prevents clicks after scrolling.
Actual Behavior
Horizontal swipe gesture release consistently triggers onPress on underlying Pressable components, causing unwanted navigation/actions.
Code Example
// Carousel with pan gesture
const panGesture = Gesture.Pan()
.minDistance(15)
.onBegin(() => {
startTranslateX.value = translateX.value;
})
.onUpdate((e) => {
translateX.value = startTranslateX.value + e.translationX;
})
.onEnd((e) => {
// Handle page change logic
});
// Underlying component that gets clicked incorrectly
<Pressable onPress={() => router.push('/article')}>
<ArticleCard />
</Pressable>
What We've Tried
Original attempts:
- setTimeout delays in gesture onEnd/onFinalize → App crashes immediately on swipe release
- Shared values to track gesture state → Still triggers clicks, no prevention
- minDistance + gesture activation thresholds → Still clicks through
- Press duration timing in ArticleCard (onPressIn/onPressOut) → Still triggers on release
- Various gesture configurations → Either crashes or doesn't prevent click-through
Additional attempts:
- Tracking gesture state with
useSharedValue and pointerEvents: 'none' → Still triggers clicks
- Distance-based swipe detection with conditional blocking → Causes crashes on gesture end
- Combining minDistance with state tracking → No improvement
- Manual press handling with gesture state checks → Unreliable and still allows click-through
Comparison with ScrollView
ScrollView correctly prevents underlying touch events when scrolling occurs, but horizontal pan gestures do not exhibit the same behavior. This suggests the issue is in how pan gestures handle touch event propagation on release.
Expected Solution
Pan gestures should automatically prevent underlying touch events when:
- The gesture has been activated (moved beyond minDistance)
- The finger is released after an active gesture
- Similar to how ScrollView prevents clicks after scrolling
Additional Context
This is a common UX pattern (horizontal carousels with clickable content) and the current behavior makes it nearly impossible to implement reliably. Users expect that after swiping, they won't accidentally trigger actions on the content they swiped over.
The fact that vertical scrolling (FlatList/ScrollView) handles this correctly suggests there's an inconsistency in gesture handling between different gesture types.
Additional Technical Details:
- Using Expo Router for navigation
- TypeScript project
- NativeWind for styling
- The issue occurs regardless of whether
minDistance is set on the pan gesture
- FlatList vertical scrolling within the same interface works correctly (doesn't trigger onPress after scrolling)
Steps to Reproduce
With Expo Snack
- Open the Expo Snack
- Start a horizontal swipe gesture to change pages
- While performing the horizontal swipe, release your finger on top of one of the colored cards
- BUG: The card's
onPress event fires even though you were swiping, not intending to press the card
Expected behavior
When performing a horizontal swipe gesture, releasing the finger on underlying Pressable components should NOT trigger their onPress events, similar to how ScrollView behaves.
Actual behavior
The underlying Pressable components' onPress events are triggered when releasing the finger after a horizontal swipe gesture, causing unintended navigation/actions.
Additional context
- This only happens with horizontal pan gestures
- Vertical scrolling (like in ScrollView) does not have this issue
- The issue occurs on both iOS and Android
- This makes horizontal carousels with clickable content unusable
With real repo
-
Clone the repositories:
git clone https://github.com/Decryptu/CryptoastAppCache.git -b dev
git clone https://github.com/Decryptu/CryptoastApp.git -b dev
-
Start the cache server (dev branch):
cd CryptoastAppCache
docker-compose up
-
Run the Expo app (dev branch):
cd CryptoastApp
npm install
expo start
-
Navigate to the Home tab
-
Perform a horizontal swipe gesture to change sections
-
Release finger on top of an article card
-
Bug: Article opens despite having just performed a swipe gesture
Note: Vertical scrolling (within the FlatList) correctly prevents click-through behavior.
A link to a Gist, an Expo Snack or a link to a repository based on this template that reproduces the bug.
https://snack.expo.dev/@decryptu/pan-gesture-release-triggers
Gesture Handler version
~2.24.0
React Native version
0.79.3
Platforms
iOS
JavaScript runtime
Hermes
Workflow
Using Expo Go
Architecture
New Architecture (Fabric)
Build type
Debug mode
Device
Real device
Device model
Apple iPhone 13 Pro
Acknowledgements
Yes
Description
When using a horizontal pan gesture for a carousel, releasing the finger after swiping triggers
onPressevents on underlyingPressablecomponents, even when the pan gesture has been active and moved significantly. This does not happen with vertical scrolling (ScrollView/FlatList), which properly prevents click-through.Environment
Expected Behavior
When a pan gesture has been active and the user has swiped horizontally, releasing the finger should NOT trigger
onPressevents on underlying components, similar to how ScrollView prevents clicks after scrolling.Actual Behavior
Horizontal swipe gesture release consistently triggers
onPresson underlyingPressablecomponents, causing unwanted navigation/actions.Code Example
What We've Tried
Original attempts:
Additional attempts:
useSharedValueandpointerEvents: 'none'→ Still triggers clicksComparison with ScrollView
ScrollView correctly prevents underlying touch events when scrolling occurs, but horizontal pan gestures do not exhibit the same behavior. This suggests the issue is in how pan gestures handle touch event propagation on release.
Expected Solution
Pan gestures should automatically prevent underlying touch events when:
Additional Context
This is a common UX pattern (horizontal carousels with clickable content) and the current behavior makes it nearly impossible to implement reliably. Users expect that after swiping, they won't accidentally trigger actions on the content they swiped over.
The fact that vertical scrolling (FlatList/ScrollView) handles this correctly suggests there's an inconsistency in gesture handling between different gesture types.
Additional Technical Details:
minDistanceis set on the pan gestureSteps to Reproduce
With Expo Snack
onPressevent fires even though you were swiping, not intending to press the cardExpected behavior
When performing a horizontal swipe gesture, releasing the finger on underlying Pressable components should NOT trigger their onPress events, similar to how ScrollView behaves.
Actual behavior
The underlying Pressable components' onPress events are triggered when releasing the finger after a horizontal swipe gesture, causing unintended navigation/actions.
Additional context
With real repo
Clone the repositories:
Start the cache server (dev branch):
cd CryptoastAppCache docker-compose upRun the Expo app (dev branch):
cd CryptoastApp npm install expo startNavigate to the Home tab
Perform a horizontal swipe gesture to change sections
Release finger on top of an article card
Bug: Article opens despite having just performed a swipe gesture
Note: Vertical scrolling (within the FlatList) correctly prevents click-through behavior.
A link to a Gist, an Expo Snack or a link to a repository based on this template that reproduces the bug.
https://snack.expo.dev/@decryptu/pan-gesture-release-triggers
Gesture Handler version
~2.24.0
React Native version
0.79.3
Platforms
iOS
JavaScript runtime
Hermes
Workflow
Using Expo Go
Architecture
New Architecture (Fabric)
Build type
Debug mode
Device
Real device
Device model
Apple iPhone 13 Pro
Acknowledgements
Yes