◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/Dev Tools
⬡ Dev Tools/2026-05-06Intermediate

Swipes and Taps Not Working in Your Rork App: 5 Common Causes and Fixes

Gestures not responding in your Rork app? This guide walks through 5 common causes — from missing GestureHandlerRootView to z-index conflicts — with concrete code fixes for each.

troubleshooting69gesturesReact Native239GestureHandlertouch events

One of the more frustrating debugging experiences in Rork app development is when swipes and taps simply stop working — and nothing shows up in the console. No error, no warning, just silence.

This typically comes down to React Native Gesture Handler configuration issues or component layering conflicts. Rork's AI generates accurate functional logic, but the touch event layer is one area that often requires manual verification. Gesture problems are also notoriously hard to reproduce consistently across devices, which is why having a systematic checklist matters.

Here are the five most common culprits, each with a concrete fix.

Cause #1: GestureHandlerRootView Is Missing

Since Expo SDK 50, wrapping your app's root in GestureHandlerRootView is required whenever you use react-native-gesture-handler. Rork sometimes omits this wrapper — particularly when generating screens with swipeable cards, draggable list items, or bottom sheet components.

// ❌ Common issue: root is not wrapped
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import RootNavigator from './navigation/RootNavigator';
 
export default function App() {
  return (
    <NavigationContainer>
      <RootNavigator />
    </NavigationContainer>
  );
}
 
// ✅ Fixed: wrap with GestureHandlerRootView
import React from 'react';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { NavigationContainer } from '@react-navigation/native';
import RootNavigator from './navigation/RootNavigator';
 
export default function App() {
  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <NavigationContainer>
        <RootNavigator />
      </NavigationContainer>
    </GestureHandlerRootView>
  );
}

Don't omit style={{ flex: 1 }} — leaving it out causes the layout to collapse to zero height. Adding this single wrapper often brings all swipe-based gestures back to life instantly.

Where to find this file in a Rork project: Look for App.tsx or app/_layout.tsx if you're using Expo Router. The GestureHandlerRootView should wrap everything, sitting just inside or just outside your navigation root.

Cause #2: An Invisible View Is Stealing Touches

When you layer components using zIndex or position: 'absolute', an invisible View sitting on top can intercept all touch events before they reach your buttons or swipeable elements. This is especially common with modals, overlays, and decorative gradient backgrounds generated by Rork.

// ❌ Problem: transparent full-screen View is consuming all touches
<View style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}>
  {/* gradient or background decoration */}
</View>
<TouchableOpacity onPress={handlePress}>
  <Text>Nothing happens when you press this</Text>
</TouchableOpacity>
 
// ✅ Fix: set pointerEvents="none" to let touches pass through
<View
  style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}
  pointerEvents="none"
>
  {/* visual-only — touch events pass through to components below */}
</View>
<TouchableOpacity onPress={handlePress}>
  <Text>Responds correctly now</Text>
</TouchableOpacity>

Quick diagnosis method: Temporarily set suspected components to display: 'none' and check if gestures start working. If they do, you've found the culprit. Add pointerEvents="none" and restore the component. This trial-and-error approach works faster than reading through nested JSX trying to spot z-index issues.

Cause #3: ScrollView and Swipe Gesture Are Competing

Placing swipe cards or horizontal sliders inside a vertical ScrollView creates ambiguity — React Native can't decide whether you want to scroll vertically or swipe horizontally, so it often does neither cleanly.

// ✅ iOS-only option: directionalLockEnabled commits to one axis
<ScrollView directionalLockEnabled={true}>
  <SwipeableCard />
</ScrollView>
 
// ✅ More reliable: use PanGesture with explicit direction thresholds
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
} from 'react-native-reanimated';
 
export function SwipeCard() {
  const translateX = useSharedValue(0);
 
  const swipeGesture = Gesture.Pan()
    .activeOffsetX([-10, 10])   // activate after 10px horizontal movement
    .failOffsetY([-5, 5])       // yield to scroll after 5px vertical movement
    .onUpdate((event) => {
      translateX.value = event.translationX;
    })
    .onEnd((event) => {
      // snap back if swipe distance is small, otherwise dismiss
      if (Math.abs(event.translationX) < 80) {
        translateX.value = withSpring(0);
      } else {
        translateX.value = withSpring(event.translationX > 0 ? 400 : -400);
      }
    });
 
  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ translateX: translateX.value }],
  }));
 
  return (
    <GestureDetector gesture={swipeGesture}>
      <Animated.View style={[styles.card, animatedStyle]}>
        {/* card content */}
      </Animated.View>
    </GestureDetector>
  );
}

The activeOffsetX / failOffsetY combination is what makes this work. With these thresholds in place, the gesture handler and the scroll container negotiate cleanly — horizontal movement triggers the swipe, vertical movement hands off to the scroll view. This pattern is reliable across both iOS and Android without any platform-specific workarounds.

For a deeper dive into gesture-based animations in Rork, see Swipe Animations with Reanimated and Gesture Handler: A Complete Guide.

Cause #4: Android Touch Delay Makes It Feel Broken

On Android, the ripple effect from TouchableNativeFeedback and Pressable can make taps feel sluggish — especially on mid-range devices. This isn't a bug, but when combined with swipe card UIs or fast interaction sequences, it's easily mistaken for a gesture failure.

// ✅ Minimize perceived touch delay with Pressable
<Pressable
  onPress={handlePress}
  android_ripple={{ color: 'rgba(0,0,0,0.08)' }}
  unstable_pressDelay={0}  // register press immediately on touch down
  style={({ pressed }) => [
    styles.card,
    { opacity: pressed ? 0.85 : 1 },
  ]}
>
  <Text>Feels responsive now</Text>
</Pressable>

unstable_pressDelay={0} has an alarming name but works reliably in production. The "unstable" label means the API surface may change in a future React Native version — check when upgrading.

For small icon buttons that are technically tappable but feel inaccurate, expand the touch area with hitSlop:

<Pressable
  onPress={handlePress}
  hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
  style={styles.iconButton}
>
  {/* icon */}
</Pressable>

A good rule of thumb: any tap target smaller than 44×44 points should have hitSlop added. Apple's Human Interface Guidelines and Google's Material Design both recommend this minimum touch target size.

Cause #5: Gestures Don't Work Inside a Modal

React Native's Modal component renders in a separate native window, outside the scope of the GestureHandlerRootView you placed at the app root. Any gesture-based components inside a Modal silently fail unless you add a second wrapper inside the Modal itself.

// ❌ Swipes inside Modal are silently ignored
import { Modal } from 'react-native';
 
<Modal visible={isVisible} transparent animationType="slide">
  <SwipeableBottomSheet />  {/* gestures don't register */}
</Modal>
 
// ✅ Add GestureHandlerRootView inside the Modal
import { Modal } from 'react-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
 
<Modal visible={isVisible} transparent animationType="slide">
  <GestureHandlerRootView style={{ flex: 1 }}>
    <SwipeableBottomSheet />  {/* now works correctly */}
  </GestureHandlerRootView>
</Modal>

This pattern comes up most often with custom bottom sheet implementations. If you're using @gorhom/bottom-sheet, check its documentation for Modal-specific setup — well-maintained libraries typically have dedicated guidance for this scenario.

Still Not Working? A Diagnostic Checklist

If none of the five causes above resolves your issue, work through these systematically:

  • Check that react-native-gesture-handler and react-native-reanimated versions are compatible — mismatched versions cause silent failures. Cross-reference with Expo's compatibility table for your SDK version.
  • Test on a production EAS Build, not Expo Go. Gesture Handler behavior can differ meaningfully between the two environments.
  • If iOS and Android behave differently, you likely need platform-specific handling with Platform.OS checks.
  • Look for any parent component with overflow: 'hidden', which can clip touch areas on Android.
  • Verify that no component in the tree has pointerEvents="none" applied unintentionally — Rork occasionally generates this to prevent interaction during loading states and forgets to remove it.

When asking Rork to fix gesture issues, be specific in your prompt. Mention that you've already confirmed GestureHandlerRootView is in place, describe which gesture type isn't working (tap, swipe, long press), and which screen it happens on. A targeted hypothesis leads to a much more useful response than a vague description.

For more on building resilient Rork apps, Error Handling and Crash Prevention Basics covers the patterns that help you catch problems before users do.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

⬡ Dev Tools2026-10-07
Japanese Headings Won't Turn Bold on Android: How to Trace and Fix a fontWeight That Does Nothing
A troubleshooting note for Rork apps where headings look bold on iPhone but stay thin on Android. How to tell the symptoms apart, pick weights through fontFamily, and verify the fix.
⬡ Dev Tools2026-09-10
I Added a Dim Screen Button, and iPhones Stayed Dark After the App Was Closed
In expo-brightness, setBrightnessAsync applies only to the current activity on Android, but changes the device brightness itself on iOS. Here is why the cleanup burden falls on one platform only, and a hook that restores brightness through AppState.
⬡ Dev Tools2026-09-04
EAS secret visibility does not keep a value out of your app — deciding prefix and visibility separately
The EXPO_PUBLIC_ prefix decides what ships inside your app; EAS visibility decides who can read it. Why stacking them blanks a value on OTA updates, and how to check your build.