Command Palette

Search for a command to run...

Event Handling in React Native: The difference between Pressable and TouchableOpacity

Event Handling in React Native

In the previous article, we became true "architects" by using Flexbox for layout and StyleSheet to beautify the application. However, no matter how gorgeous your interface is, it's still just a static picture if nothing happens when the user touches it.

In this article, we will turn the application into a "living" entity that listens to and responds to every swipe and touch from the user. Let's explore how to handle events (Event Handling) in React Native!

1. The surprising truth about the Button component in React Native

If you have ever programmed for the Web, your first instinct when you want to create a button is to look for the <button> tag. React Native also provides a Core Component named <Button>.

However, there is a harsh truth: Professional developers rarely use it.

Why is that? Because the native <Button> component in React Native is very rigid. You cannot add a style property to it. You cannot change the font, you cannot round the corners, and worst of all: Its interface on iOS and Android looks completely different!

To have a beautiful, consistent button across all devices that is 100% customizable using Flexbox, we have to use the component family named Touchable or the newest generation, Pressable.

2. The Era of Touchable: TouchableOpacity

This is the most widely used "hero" for creating buttons throughout the history of React Native.

True to its name (Opacity), when the user touches this component, the entire content inside will dim slightly, creating an extremely natural and familiar visual feedback effect on phones.

How to turn anything into a button

You can wrap TouchableOpacity around a piece of Text, an image, or a massive View block.

Let's take the example of building an interface for a strategy guide app. When users want to lock in a precise synergy team (ensuring role compatibility, such as combining Mid Lane and Jungle), they will press a confirm button.

import React, { useState } from 'react'
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'

export default function SynergySelector() {
  const [selectedSynergy, setSelectedSynergy] = useState('No team selected yet')

  const handleSelectDuo = () => {
    // Update state when the button is pressed.
    // Here we choose a standard Mid - Jungle duo.
    setSelectedSynergy('Katarina (Mid) & Amumu (Jungle)')
  }

  return (
    <View style={styles.container}>
      <Text style={styles.statusText}>Currently selecting: {selectedSynergy}</Text>

      {/* Custom designed button with TouchableOpacity */}
      <TouchableOpacity
        style={styles.button}
        onPress={handleSelectDuo} // Catch press event
        activeOpacity={0.7} // Customize opacity on press (default is 0.2)
      >
        <Text style={styles.buttonText}>Confirm Synergy</Text>
      </TouchableOpacity>
    </View>
  )
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
  statusText: { fontSize: 18, marginBottom: 20, color: '#333' },
  button: {
    backgroundColor: '#0984e3',
    paddingVertical: 12,
    paddingHorizontal: 30,
    borderRadius: 8,
    elevation: 3, // Create drop shadow on Android
    shadowColor: '#000', // Create drop shadow on iOS
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.2,
  },
  buttonText: { color: 'white', fontSize: 16, fontWeight: 'bold' },
})

(Note: If you use TouchableWithoutFeedback, the button will receive the event but will not have any dimming or color-changing effects. It is often used for hidden actions, for example: Tapping on the empty space outside to hide the keyboard).

3. The Future of Interaction: The Pressable Component

Although TouchableOpacity is great, as your application grows more complex, you sometimes want button effects that are richer than just "dimming". For example: You want the button to change to red when held down, and turn back to blue when released.

That's why React Native introduced Pressable. This is the most modern, flexible component and is recommended to replace the entire Touchable family in new projects.

The power of the pressed state

The most "valuable" feature of Pressable is that it allows you to pass a function into the style property to track whether the button is currently being pressed or not.

import React from 'react'
import { Pressable, Text, StyleSheet, View } from 'react-native'

export default function ModernButton() {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Pressable
        onPress={() => console.log('Pressed!')}
        style={({ pressed }) => [
          styles.baseButton,
          // If being pressed (pressed = true), change background to dark gray
          pressed ? { backgroundColor: '#2d3436' } : { backgroundColor: '#00b894' },
        ]}
      >
        {({ pressed }) => <Text style={styles.text}>{pressed ? 'Holding tight...' : 'Touch me!'}</Text>}
      </Pressable>
    </View>
  )
}

const styles = StyleSheet.create({
  baseButton: {
    padding: 15,
    borderRadius: 10,
    minWidth: 150,
    alignItems: 'center',
  },
  text: { color: 'white', fontWeight: 'bold' },
})

With Pressable, you have 100% control over the interactive feel without having to write complex code to track animations.

4. Extended Touch Event Types

Both TouchableOpacity and Pressable support more event milestones than just a single tap (onPress). You can leverage them to create advanced features:

  • onPress: Triggered when the user touches and releases (The most common click action).
  • onLongPress: Triggered when the user presses and holds the button for a sufficiently long time (about 500ms). Often used to open a sub-menu or delete an item.
  • onPressIn: Triggered the exact moment the finger touches the screen (even before releasing).
  • onPressOut: Triggered the moment the finger leaves the screen.

Pro tip: Pressable also has a hitSlop property. If you have a small button (like an X button to close a popup), you can use hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }} to expand the touchable area, making it easier for users with larger fingers to hit it without changing the actual visual size of the button on the interface.

Conclusion: The application is now interactive

For a React Native application to respond smoothly to interactions:

  1. Avoid using the default <Button> if you want a highly aesthetic and consistent interface.
  2. Use TouchableOpacity for cases involving quick buttons that need a simple dimming effect.
  3. Switch to using Pressable for new projects or when you need deep customization of the display state when pressed, as well as leveraging hitSlop to optimize user experience (UX).

Up to this point, you know how to draw interfaces and make them "listen". But real-world applications often contain hundreds or thousands of data items (like a Facebook newsfeed or a product list). If you display them all at once, the phone will immediately freeze!

To solve this tricky problem, we will move on to the next lessons.

Related Posts

How to Call APIs in React Native: Fetch Data & JSON Parsing Guide

A detailed guide on how to call APIs in React Native. Master the technique of using fetch, axios combined with useEffect, useState to load and display server data smoothly.

What is React Native? Why use it for Mobile programming?

Discover the power of React Native and the Expo platform that helps you build mobile apps quickly without the hassle of complex setups.

Guide to Setting Up React Native & Expo Environment in 15 Minutes

Afraid of complex mobile programming environment setups? A detailed guide on using Expo Go and Node.js to run React Native apps instantly.

How to Use FlatList in React Native: Display Lists Without Lag

Solve the problem of displaying large data lists with FlatList and SectionList. A guide to memory optimization and smooth scrolling speed.