Pressable — what it is, handling presses in React Native

Author: IT Sectr Published: 2026-07-06 Reading time: 10 min

Pressable is a modern React Native component for handling touches, replacing the legacy TouchableHighlight, TouchableOpacity, and TouchableWithoutFeedback. Pressable provides a unified API with detection of pressed, hovered, and focused states. The component was introduced in React Native 0.63 and is recommended by Meta for all new projects. Learn more in Meta’s documentation.

Key Takeaways

  • Pressable — a universal touch handling component with pressed, hovered, and focused state support
  • API includes onPress, onLongPress, onPressIn, onPressOut callbacks and state-based styling function
  • hitSlop extends the touch area beyond the visible component bounds to improve UX
  • Touchable replacement — Pressable unifies the API of all Touchable components into one flexible interface
  • Accessibility — the component supports ARIA roles and automatically handles VoiceOver and TalkBack

What is Pressable?

Pressable is a React Native component that provides a unified interface for handling all types of touches. Unlike three different Touchable components (TouchableHighlight, TouchableOpacity, TouchableWithoutFeedback), Pressable replaces them all with one flexible state and styling system.

The component was introduced in React Native 0.63 (September 2020). According to Meta (2026), 70% of new React Native projects use Pressable instead of Touchable components. Pressable solves the key problem of Touchable — a fragmented API and the need to switch between components for different effects.

Pressable Philosophy

Unlike TouchableOpacity, where the press effect is hardcoded (opacity change), Pressable provides a function that receives the current state. The developer decides how to visually respond to a press: change color, scale, shadow, or a combination of effects. This gives full control over UX.

Pressable states: pressed, hovered, focused

Pressable defines three interaction states: pressed (finger on screen), hovered (cursor over element on Web/TV), focused (element in keyboard focus). Each state triggers the corresponding callback and is passed to the style function and the child render function.

StateConditionTypical reaction
pressedFinger on screen or click heldOpacity, scale, or background color change
hoveredCursor over element (Web, TV)Highlight, shadow, underline
focusedElement in keyboard focusOutline, border, color change

Important: hovered and focused only work on platforms with pointer support (Web, Android TV, Apple TV). On mobile devices, only pressed is available. For cross-platform applications, design visual reactions considering this limitation.

js
<Pressable
  style={({ pressed }) => [
    styles.button,
    pressed && styles.buttonPressed,
  ]}
  onPress={handlePress}>
  {({ pressed }) => (
    <Text style={pressed ? styles.textPressed : styles.text}>
      {pressed ? 'Release' : 'Press'}
    </Text>
  )}
</Pressable>

Pressable API and callbacks

Pressable API includes four main callbacks: onPress (full press with release), onLongPress (long press), onPressIn (touch start), and onPressOut (touch end). The combination of onPressIn and onPressOut allows creating custom animations.

Additional props: delayLongPress (long press delay, default 500 ms), pressRetentionOffset (area beyond which the press is cancelled), android_ripple (ripple effect on Android). Note: Ripple only works on Android 5+.

js
<Pressable
  onPress={() => console.log('Pressed')}
  onLongPress={() => console.log('Long press')}
  onPressIn={() => console.log('Finger down')}
  onPressOut={() => console.log('Finger up')}
  delayLongPress={300}
  android_ripple={{ color: 'rgba(0,0,0,0.1)', borderless: false }}
  style={styles.button}>
  <Text>Press me</Text>
</Pressable>

onPress is only called if the finger is lifted within the component area (accounting for pressRetentionOffset). If the user moves their finger outside the bounds, onPress is not triggered, preventing false presses. onPressOut is called in any case upon release.

hitSlop: expanding the touch area

hitSlop is a Pressable prop that extends the touch area beyond the visible component bounds. This is critical for small elements: icons, checkboxes, radio buttons. Apple HIG recommends a minimum touch target size of 44×44 points. hitSlop allows meeting this requirement without changing the visual size.

hitSlop accepts an object { top, bottom, left, right } or a single number for all sides. Values are specified in logical pixels (dp/pt). For 24×24 icons, a hitSlop of at least 10–12 on each side is recommended to achieve the 44×44 touch target.

js
<Pressable
  hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
  onPress={handleIconPress}
  style={styles.iconButton}>
  <Icon name="star" size={24} />
</Pressable>

pressRetentionOffset — the inverse of hitSlop: defines the area the user can move outside the component bounds without cancelling the press. Defaults to hitSlop. If you need the press to persist when moving outside the bounds, increase pressRetentionOffset.

Pressable vs Touchable: when to switch

Pressable vs Touchable — a key question when choosing a component for handling touches. TouchableOpacity, TouchableHighlight, and TouchableWithoutFeedback are legacy components that will not be removed but will not receive new features. Meta recommends Pressable for new projects.

Key advantages of Pressable: a unified API for all effect types, access to the pressed state for custom styling, hovered/focused state support, hitSlop and pressRetentionOffset, onLongPress callback without additional configuration. TouchableOpacity is only suitable for simple opacity changes.

ScenarioTouchablePressable
Simple pressTouchableOpacityPressable + opacity in style
Background highlightTouchableHighlightPressable + backgroundColor
No visual effectTouchableWithoutFeedbackPressable with empty style
Long pressonLongPress on any TouchableonLongPress on Pressable
Custom animationAnimated + onPressIn/OutPressable + useAnimatedStyle
Ripple on AndroidTouchableNativeFeedbackPressable + android_ripple

Pressable usage examples

Pressable allows creating complex interactive elements with minimal code. Below is an example of an animated button with scale change on press and ripple effect on Android. Such a button replaces the TouchableOpacity + Animated combination.

js
const AnimatedButton = ({ title, onPress }) => {
  const scale = React.useRef(new Animated.Value(1)).current;

  const handlePressIn = () => {
    Animated.spring(scale, {
      toValue: 0.96,
      useNativeDriver: true,
    }).start();
  };

  const handlePressOut = () => {
    Animated.spring(scale, {
      toValue: 1,
      friction: 3,
      useNativeDriver: true,
    }).start();
  };

  return (
    <Pressable
      onPress={onPress}
      onPressIn={handlePressIn}
      onPressOut={handlePressOut}
      android_ripple={{ color: 'rgba(255,255,255,0.3)' }}
      style={styles.button}>
      <AnimatedView style={[styles.inner, { transform: [{ scale }] }]}>
        <Text style={styles.text}>{title}</Text>
      </AnimatedView>
    </Pressable>
  );
};

Important: use useNativeDriver: true for animations in Pressable. This offloads the animation to the native thread, preventing frame drops during fast presses. Native driver is supported for transform and opacity on all platforms.

Frequently Asked Questions

Can I use Pressable instead of TouchableOpacity without changing the code?

No, Pressable has a different API. TouchableOpacity automatically applies opacity on press. Pressable requires explicit style specification via a state function. The replacement is trivial: pass style={({ pressed }) => [{ opacity: pressed ? 0.5 : 1 }]}.

How to create a ripple effect like in Material Design?

Use the android_ripple prop with an object { color, borderless }. The ripple color is specified in rgba format. For round buttons, use borderless: true. Ripple only works on Android 5+. On iOS, use custom animation.

Why doesn’t onPress fire during fast scrolling?

Pressable has built-in protection against accidental presses during scrolling. If the user scrolls a list, onPress is not called. This behavior can be configured via pressRetentionOffset and delayPressIn.

How to track long press with Pressable?

Use the onLongPress prop — built-in long press support. The delay is configurable via delayLongPress (default 500 ms). For context menus and drag-and-drop, combine onLongPress with onPressIn.

Does Pressable support keyboard navigation?

Yes, Pressable supports the focused state for keyboard navigation on Android TV, Apple TV, and Web. Use styling via { focused } to display focus. On mobile devices, the focused state is not applicable.

Summary

  • Pressable — a universal React Native component for handling touches, replacing TouchableOpacity, TouchableHighlight, and TouchableWithoutFeedback
  • States pressed, hovered, focused are passed to the style function, allowing customization of the reaction for each scenario
  • hitSlop extends the touch target to 44×44 points without changing the visual size, improving UX on small elements
  • API includes onPress, onLongPress, onPressIn, onPressOut with configurable delay via delayLongPress
  • android_ripple adds a Material Design ripple effect on Android 5+ with customizable color and shape
  • Migration from Touchable requires replacing automatic effects with explicit styling via a state function
  • Animated + Pressable create smooth press animations with useNativeDriver for performance

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also