Skip to content

React Native - Buttons

React Native provides several ways to create interactive buttons and touchable areas. This chapter covers the basic Button component and more customizable touchable components like TouchableOpacity, TouchableHighlight, TouchableWithoutFeedback, and the modern Pressable.

The Button component is a simple, pre-styled button. It’s good for quick use but offers limited customization.

ButtonExample.js

import React from 'react';
import { View, Button, Alert, StyleSheet } from 'react-native';
const ButtonExample = () => {
const handlePress = () => {
Alert.alert('Button Pressed!', 'You tapped the basic button.');
};
return (
<View style={styles.container}>
<Button
title="Press Me"
onPress={handlePress}
color="#841584" // Optional: customize color (iOS text, Android background)
// accessibilityLabel="Learn more about this purple button" // For accessibility
// disabled={true} // To disable the button
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
}
});
export default ButtonExample;

This will render a platform-standard button. On iOS, the color prop changes the text color. On Android, color changes the background color (for Android API level 21+).

TouchableOpacity is a wrapper that dims the opacity of its content when pressed, providing visual feedback. It’s highly customizable as you can style its child components.

TouchableOpacityExample.js

import React from 'react';
import { View, TouchableOpacity, Text, StyleSheet, Alert } from 'react-native';
const TouchableOpacityExample = () => {
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.touchableOpacityButton}
onPress={() => Alert.alert('TouchableOpacity', 'Opacity effect on press!')}
activeOpacity={0.7} // Opacity when active (pressed), default is 0.2
>
<Text style={styles.buttonText}>Custom Button (Opacity)</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20
},
touchableOpacityButton: {
backgroundColor: '#007bff',
paddingVertical: 12,
paddingHorizontal: 25,
borderRadius: 8,
elevation: 3, // Android shadow
shadowColor: '#000', // iOS shadow
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 3.84,
},
buttonText: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
textAlign: 'center',
}
});
export default TouchableOpacityExample;

Pressing this button will momentarily reduce its opacity, providing a common touch feedback.

TouchableHighlight darkens the background of its content (the underlay) when pressed. You must provide an underlayColor prop.

TouchableHighlightExample.js

import React from 'react';
import { View, TouchableHighlight, Text, StyleSheet, Alert } from 'react-native';
const TouchableHighlightExample = () => {
return (
<View style={styles.container}>
<TouchableHighlight
style={styles.touchableHighlightButton}
onPress={() => Alert.alert('TouchableHighlight', 'Highlight effect on press!')}
underlayColor="#0056b3" // Color shown when pressed
>
<Text style={styles.buttonText}>Custom Button (Highlight)</Text>
</TouchableHighlight>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20
},
touchableHighlightButton: {
backgroundColor: '#17a2b8',
paddingVertical: 12,
paddingHorizontal: 25,
borderRadius: 8,
},
buttonText: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
textAlign: 'center',
}
});
export default TouchableHighlightExample;

When pressed, the button’s background will change to the underlayColor.

Pressable is a more modern and versatile core component that detects various stages of press interactions on its defined child. It provides more fine-grained control over visual feedback and interaction states (e.g., pressed, hover, focus).

PressableExample.js

import React from 'react';
import { View, Pressable, Text, StyleSheet, Alert } from 'react-native';
const PressableExample = () => {
return (
<View style={styles.container}>
<Pressable
onPress={() => Alert.alert('Pressable', 'Standard press!')}
onLongPress={() => Alert.alert('Pressable', 'Long press!')}
// The `style` prop can be a function to change style based on pressed state
style={({ pressed }) => [
styles.pressableButton,
{ backgroundColor: pressed ? 'rgb(210, 230, 255)' : '#28a745' }
]}
// android_ripple={{ color: 'grey', borderless: false }}
// hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
>
{({ pressed }) => (
<Text style={styles.buttonText}>
{pressed ? 'Pressed!' : 'Press Me (Pressable)'}
</Text>
)}
</Pressable>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20
},
pressableButton: {
paddingVertical: 12,
paddingHorizontal: 25,
borderRadius: 8,
elevation: 3,
},
buttonText: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
textAlign: 'center',
}
});
export default PressableExample;

Pressable offers features like:

  • onPressIn, onPressOut, onLongPress.
  • Functional style and children props to dynamically change based on interaction state (pressed).
  • android_ripple for Android’s ripple effect.
  • hitSlop to extend the touchable area without changing the layout.

This component provides Android’s native ripple effect. It only works on Android. For cross-platform solutions, Pressable with android_ripple is preferred, or use TouchableOpacity for a consistent feel.

// TouchableNativeFeedbackExample.js (Android Only)
import React from 'react';
import { View, TouchableNativeFeedback, Text, StyleSheet, Platform, Alert } from 'react-native';
const TouchableNativeFeedbackExample = () => {
if (Platform.OS === 'android') {
return (
<View style={styles.container}>
<TouchableNativeFeedback
onPress={() => Alert.alert('Native Feedback', 'Ripple effect!')}
background={TouchableNativeFeedback.Ripple('rgba(255,255,255,0.3)', false)} // color, borderless
useForeground={true} // Ripple effect on foreground, good for rounded corners
>
<View style={styles.nativeFeedbackButton}>
<Text style={styles.buttonText}>Button (Native Ripple)</Text>
</View>
</TouchableNativeFeedback>
</View>
);
}
return (
<View style={styles.container}><Text>TouchableNativeFeedback is Android-only.</Text></View>
);
};
// (Styles similar to other examples)
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20 },
nativeFeedbackButton: { backgroundColor: '#ffc107', paddingVertical: 12, paddingHorizontal: 25, borderRadius: 8, alignItems: 'center', justifyContent: 'center' },
buttonText: { color: '#212529', fontSize: 16, fontWeight: 'bold' }
});
export default TouchableNativeFeedbackExample;

This component handles touch events but provides no visual feedback. It’s useful for creating custom touch interactions where default feedback is not desired.

// TouchableWithoutFeedbackExample.js
import React from 'react';
import { View, TouchableWithoutFeedback, Text, StyleSheet, Alert } from 'react-native';
const TouchableWithoutFeedbackExample = () => {
return (
<View style={styles.container}>
<TouchableWithoutFeedback onPress={() => Alert.alert('No Feedback', 'Touched!')}>
<View style={styles.noFeedbackView}>
<Text>Touch Area (No Visual Feedback)</Text>
</View>
</TouchableWithoutFeedback>
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
noFeedbackView: { padding: 20, backgroundColor: '#e9ecef', borderWidth: 1, borderColor: '#ced4da' }
});
export default TouchableWithoutFeedbackExample;

Choosing the right touchable component depends on the desired user experience and level of customization. Pressable is often the best general-purpose choice for new development. Learn more at: https://reactnative.dev/docs/handling-touches