PanResponder: The Gesture State Machine
PanResponder turns raw touch events into a single, stateful gesture, like dragging an object. It's used to build draggable elements by providing a gestureState object with velocity and distance. The footgun is confusing moveX/Y with dx/dy.
Why it exists
The raw touch system in mobile OSes is low-level. Building a simple "drag" requires tracking start points, current points, and deciding which component "owns" the touch. PanResponder was created to abstract this complex state management into a predictable wrapper.
The mental model
Think of PanResponder as a gesture negotiator and state tracker. It asks, "Should I handle this touch?" If it wins the negotiation, it starts tracking the gesture and provides a rich gestureState object with all the info you need, like how far the finger has moved (dx, dy) and how fast (vx, vy).
How it works
You create a PanResponder using PanResponder.create(), passing a configuration object of callbacks that define the gesture's lifecycle. First, you use onStartShouldSetPanResponder or onMoveShouldSetPanResponder to "claim" a gesture by returning true. Once granted (onPanResponderGrant), you can react to movement with onPanResponderMove. The gestureState object passed to these callbacks contains derived values like dx, dy (accumulated distance), and numberActiveTouches. You apply these handlers to a View using the {...panResponder.panHandlers} spread prop.
When to use it
Use PanResponder when you need to create custom gestures beyond a simple tap. It's ideal for dragging elements, basic pinching (by tracking numberActiveTouches), or any interaction where you need the gesture's velocity or total distance traveled. It is designed to work with the Animated API to translate gesture data into smooth UI animations.
When not to use it
For simple presses or long presses, React Native's built-in Pressable or TouchableOpacity components are simpler. PanResponder is overkill for basic button-like behavior. Its power lies in handling continuous, stateful gestures, not discrete actions.
One canonical example
A draggable card. In onPanResponderMove, you use the gestureState.dx and gestureState.dy values to update the position of an Animated.View. When the user lets go (onPanResponderRelease), you can animate the card back to its origin. The dx and dy are perfect for this because they represent the total change from where the drag started, not the absolute screen coordinates.
Interview question
When dragging an element with PanResponder, which gestureState properties should be used to update its position based on the total distance moved from the gesture's start?
- a.gestureState.numberActiveTouches
- b.gestureState.dx and gestureState.dyCorrect
- c.gestureState.moveX and gestureState.moveY
- d.gestureState.vx and gestureState.vy
Why? this is the answer
The card explicitly states that 'dx and dy are perfect for this because they represent the total change from where the drag started, not the absolute screen coordinates.' moveX/Y represent absolute screen coordinates, not the accumulated distance from the drag's origin.
Just read this? Test yourself on what you have been reading.
Read the original → reactnative.dev
- #react-native
- #gestures
- #ui
- #animation
Put your scrolling time to good use
Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on react-native — each one lists the topics its interview covers.
See open roles