Skip to main content

Gesture handling in React Native with react-native-gesture-handler

ยท 4 min read
Full Stack Developer
Last updated on January 16, 2026

Gesture handling in React Native

Touch and gesture interactions are the core of great mobile UX. If your gestures feel laggy or inconsistent, users will feel it immediately. In this guide, you will learn how to implement smooth, native-feel gestures with react-native-gesture-handler using modern APIs, plus the setup steps that avoid the most common pitfalls.

If you want to start from a production-ready foundation, explore our React Native templates and ship your next app faster.

Mega Bundle Sale is ON! Get ALL of our React Native codebases at 90% OFF discount ๐Ÿ”ฅ

Get the Mega Bundle

Installationโ€‹

Expoโ€‹

expo install react-native-gesture-handler

React Native CLIโ€‹

yarn add react-native-gesture-handler

Then ensure your entry file (e.g., index.js) imports the library before any other imports:

import "react-native-gesture-handler";

Finally, wrap your app in GestureHandlerRootView:

import React from "react";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import App from "./App";

export default function Root() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<App />
</GestureHandlerRootView>
);
}

If you plan to animate gestures smoothly, install Reanimated as well:

yarn add react-native-reanimated

The new Gesture API works great with Reanimated and keeps animations on the UI thread for smooth performance.

Tap gesture (press effect)โ€‹

import React from "react";
import { View, Text } from "react-native";
import { Gesture, GestureDetector } from "react-native-gesture-handler";
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from "react-native-reanimated";

export default function TapCard() {
const scale = useSharedValue(1);

const tap = Gesture.Tap()
.onBegin(() => {
scale.value = 0.96;
})
.onFinalize(() => {
scale.value = withSpring(1);
});

const style = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }],
}));

return (
<GestureDetector gesture={tap}>
<Animated.View style={[{ padding: 16, backgroundColor: "#111", borderRadius: 12 }, style]}>
<Text style={{ color: "#fff" }}>Tap me</Text>
</Animated.View>
</GestureDetector>
);
}

Pan gesture (drag a card)โ€‹

import React from "react";
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from "react-native-reanimated";
import { Gesture, GestureDetector } from "react-native-gesture-handler";

export default function DraggableCard() {
const x = useSharedValue(0);
const y = useSharedValue(0);

const pan = Gesture.Pan()
.onChange((e) => {
x.value += e.changeX;
y.value += e.changeY;
})
.onEnd(() => {
x.value = withSpring(0);
y.value = withSpring(0);
});

const style = useAnimatedStyle(() => ({
transform: [{ translateX: x.value }, { translateY: y.value }],
}));

return (
<GestureDetector gesture={pan}>
<Animated.View style={[{ width: 160, height: 120, backgroundColor: "#0f172a", borderRadius: 16 }, style]} />
</GestureDetector>
);
}

Working with ScrollView and nested gesturesโ€‹

When gestures compete (e.g., a card inside a ScrollView), use simultaneousWithExternalGesture or requireExternalGestureToFail to control priority:

const scroll = Gesture.Native();
const pan = Gesture.Pan().simultaneousWithExternalGesture(scroll);

This keeps your drag interactions smooth without blocking the main scroll.

Performance tipsโ€‹

  • Keep logic inside gesture callbacks light. Heavy work should be offloaded or deferred.
  • Prefer Reanimated values (useSharedValue) for animation-driven interactions.
  • Only use runOnJS when you must update React state.

Mega Bundle Sale is ON! Get ALL of our React Native codebases at 90% OFF discount ๐Ÿ”ฅ

Get the Mega Bundle

Troubleshootingโ€‹

"GestureHandlerRootView is not found"
Make sure your app is wrapped with GestureHandlerRootView and that the library import is at the top of your entry file.

Gestures feel laggy
Check that you are using the new Gesture API with Reanimated, not JS-based animated values.

Touch conflicts in lists
Use simultaneousWithExternalGesture or require the scroll gesture to fail before your pan begins.

Looking for a custom mobile application?

Our team of expert mobile developers can help you build a custom mobile app that meets your specific needs.

Get in Touch

Conclusionโ€‹

The best mobile apps feel effortless because their gestures are smooth, native, and predictable. With react-native-gesture-handler, you can build interactions that feel at home on both iOS and Android.

If you want to ship faster, start from a production-ready codebase with our React Native templates.

Or get everything at once with the All Access pass: All Access - Mega Bundle