Using Pressable, Button, and Touchable Components in React Native
Course: React Native Training
Topic: Using Pressable, Button, and Touchable Components
Course Link: React Native Training at JustAcademy
Demo Link: Register for a Course Demo
Website: JustAcademy Official Website
1. Introduction to Touch Interactions in React Native
Touch interactions are an essential part of mobile application development. Users interact with mobile applications by tapping buttons, selecting cards, submitting forms, opening menus, confirming actions, and pressing and holding interface elements.
React Native provides several built-in components for handling touch interactions, including Pressable, Button, TouchableOpacity, TouchableHighlight, and TouchableWithoutFeedback. These components help developers detect user actions and provide feedback when an element is pressed.
Each component has a different purpose. The Button component provides a simple platform-rendered button, Pressable supports flexible styling and detailed press events, and Touchable components provide different types of touch feedback.
Learning Objectives
- Understand how touch interactions work in React Native.
- Learn the purpose and usage of Pressable.
- Create basic buttons using the Button component.
- Understand TouchableOpacity and TouchableHighlight.
- Learn when TouchableWithoutFeedback is appropriate.
- Handle onPress, onPressIn, onPressOut, and onLongPress events.
- Manage disabled buttons and button states.
- Build reusable, accessible buttons with custom styling.
- Implement practical examples and troubleshoot common issues.
2. Understanding Touch Events
A touch event occurs when a user interacts with an element on the screen. For example, when a user taps a Login button, the application can validate the form and navigate to the next screen.
Touch components connect a user's physical interaction with JavaScript functions. These functions are commonly called event handlers or callback functions.
Basic Example
import React from 'react';
import { View, Text, Pressable, Alert } from 'react-native';
export default function App() {
const handlePress = () => {
Alert.alert('Success', 'You pressed the button!');
};
return (
<View>
<Pressable onPress={handlePress}>
<Text>Press Me</Text>
</Pressable>
</View>
);
}
Explanation
Pressable makes the wrapped content respond to touch interactions.
onPress specifies the function that runs when the press is recognized.
handlePress contains the action performed after the user presses the component.
Alert.alert() displays a native alert dialog.
Text provides the visible label for the pressable element.
Touch handlers are useful for navigation, form submission, changing application state, selecting list items, and opening or closing interface elements.
3. What Is Pressable?
Pressable is a built-in React Native component that makes its children respond to press interactions. It supports different event callbacks and allows developers to change the appearance of an element depending on whether it is being pressed.
Pressable is a flexible choice for building custom buttons, interactive cards, clickable list items, menu options, and other touch-enabled elements. It is generally a good starting point for new custom interactive components.
Basic Syntax
<Pressable onPress={() => console.log('Pressed')}>
<Text>Click Here</Text>
</Pressable>
Example: Styled Pressable Button
import React from 'react';
import {
View,
Text,
Pressable,
StyleSheet,
Alert
} from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<Pressable
style={styles.button}
onPress={() => Alert.alert('Hello', 'Welcome to React Native!')}
>
<Text style={styles.buttonText}>Get Started</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
button: {
backgroundColor: '#2563eb',
paddingVertical: 14,
paddingHorizontal: 28,
borderRadius: 8
},
buttonText: {
color: '#ffffff',
fontSize: 16,
fontWeight: 'bold'
}
});
Important Features of Pressable
- Supports custom styling and layout.
- Provides callbacks for press interactions.
- Can change its style based on the pressed state.
- Supports long-press interactions.
- Can be disabled when an action is unavailable.
- Supports accessibility-related properties.
- Can wrap complex content such as icons, text, and images.
4. Important Pressable Props
Props configure the behavior and appearance of a Pressable component.
| Prop |
Purpose |
Example |
onPress |
Runs when a press is successfully recognized. |
onPress={handlePress} |
onPressIn |
Runs when the press interaction begins. |
onPressIn={handlePressIn} |
onPressOut |
Runs when the press interaction ends. |
onPressOut={handlePressOut} |
onLongPress |
Runs when the user presses and holds long enough. |
onLongPress={handleLongPress} |
disabled |
Disables the press interaction. |
disabled={true} |
style |
Defines the component's visual style. |
style={styles.button} |
hitSlop |
Expands the area from which a touch can begin. |
hitSlop={10} |
delayLongPress |
Configures the delay before a long press is recognized. |
delayLongPress={800} |
android_ripple |
Configures Android ripple feedback where supported. |
android_ripple={'{ color: "#dddddd" }'} |
accessibilityRole |
Communicates the element's role to accessibility services. |
accessibilityRole="button" |
Always check the documentation for the React Native version used by your project, because supported properties and platform behavior can vary.
5. Understanding onPress
The onPress callback is one of the most commonly used touch event handlers. It runs when the interaction is recognized as a completed press rather than a cancelled gesture.
Example
import React from 'react';
import { View, Text, Pressable, Alert } from 'react-native';
export default function App() {
const handlePress = () => {
Alert.alert('Button Pressed');
};
return (
<View>
<Pressable onPress={handlePress}>
<Text>Submit</Text>
</Pressable>
</View>
);
}
Common Uses
- Submitting forms.
- Opening another screen.
- Saving user preferences.
- Adding a product to a cart.
- Opening a modal or menu.
- Updating a counter or selection.
Pass a function reference such as onPress={handlePress} rather than calling the function during rendering with onPress={handlePress()}. Calling it immediately may execute the action before the user interacts with the component.
6. Understanding onPressIn and onPressOut
Pressable provides callbacks for the beginning and end of a touch interaction. These events can be useful when implementing custom animations, visual feedback, or interaction tracking.
- onPressIn: Runs when the press interaction begins.
- onPressOut: Runs when the press interaction ends.
- onPress: Runs when the interaction is recognized as a completed press.
Example
import React from 'react';
import { View, Text, Pressable, Alert } from 'react-native';
export default function App() {
return (
<View style={{ padding: 30 }}>
<Pressable
onPressIn={() => console.log('Press started')}
onPressOut={() => console.log('Press ended')}
onPress={() => Alert.alert('Action completed')}
>
<Text>Press and Release</Text>
</Pressable>
</View>
);
}
These callbacks may run in sequence as the user interacts with the component. Do not assume that every onPressIn event will result in an onPress event; the gesture can be cancelled.
7. Handling Long Press with Pressable
A long press occurs when a user presses and holds an element for a specified duration. It is useful for contextual menus, item selection, additional options, and certain editing actions.
Example
import React from 'react';
import { View, Text, Pressable, Alert } from 'react-native';
export default function App() {
return (
<View style={{ padding: 20 }}>
<Pressable
onPress={() => Alert.alert('Tap', 'Short press detected')}
onLongPress={() => Alert.alert('Long Press', 'You held the button')}
delayLongPress={700}
>
<Text>Tap or Hold This Text</Text>
</Pressable>
</View>
);
}
The delayLongPress property controls the delay before the long-press callback is triggered. Choose a duration that feels natural for the interaction and test it on real devices.
8. Dynamic Styling with Pressable
One of Pressable's useful features is its ability to receive a function for the style prop. The function receives a state object containing information about the current press interaction.
Example
import React from 'react';
import { View, Text, Pressable, StyleSheet } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<Pressable
style={({ pressed }) => [
styles.button,
pressed && styles.buttonPressed
]}
onPress={() => console.log('Button pressed')}
>
{({ pressed }) => (
<Text style={styles.buttonText}>
{pressed ? 'Pressing...' : 'Press Me'}
</Text>
)}
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
button: {
backgroundColor: '#2563eb',
padding: 16,
borderRadius: 8
},
buttonPressed: {
backgroundColor: '#1e40af',
transform: [{ scale: 0.98 }]
},
buttonText: {
color: '#ffffff',
fontSize: 16,
fontWeight: 'bold'
}
});
Explanation
- The style function receives the current pressed state.
- The base style is always applied.
- The pressed style is added only while the component is pressed.
- The child render function can also display different content according to the pressed state.
Dynamic styling can provide useful feedback without maintaining a separate React state variable for a simple pressed interaction.
9. What Is the Button Component?
The React Native Button component is a built-in component for creating simple buttons. It provides a standard platform-rendered appearance and requires very little code.
Button is useful when you need a basic action such as submitting a form, confirming a choice, or triggering a simple function without building a fully customized button design.
Basic Syntax
import React from 'react';
import { View, Button, Alert } from 'react-native';
export default function App() {
return (
<View>
<Button
title="Click Me"
onPress={() => Alert.alert('Hello', 'Button clicked')}
/>
</View>
);
}
Important Button Props
| Prop |
Description |
title |
The text displayed on the button. |
onPress |
The function executed when the button is pressed. |
color |
Sets the button's platform-supported color treatment. |
disabled |
Disables the button when set to true. |
accessibilityLabel |
Provides an accessible description of the button. |
testID |
Provides an identifier useful for automated testing. |
The Button component has limited styling options compared with Pressable and Touchable components. Its appearance also varies by platform. Use Pressable when you need complete control over layout, icons, typography, borders, and pressed-state styling.
10. Creating Buttons with Different Actions
Multiple Button components can trigger different functions. This pattern is useful for simple action menus, confirmation screens, and basic demonstrations.
import React from 'react';
import { View, Button, Alert, StyleSheet } from 'react-native';
export default function App() {
const handleSave = () => {
Alert.alert('Saved', 'Your information has been saved.');
};
const handleCancel = () => {
Alert.alert('Cancelled', 'The operation was cancelled.');
};
return (
<View style={styles.container}>
<Button title="Save" onPress={handleSave} color="#16a34a" />
<View style={styles.spacing} />
<Button title="Cancel" onPress={handleCancel} color="#dc2626" />
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 20
},
spacing: {
height: 12
}
});
In this example, each button has a separate handler. The color property adjusts the button's color treatment, but exact rendering differs across platforms.
11. Disabling a Button
A disabled button prevents users from triggering an action when it is unavailable. For example, a Submit button may remain disabled until all required form fields are completed.
Button Example
<Button
title="Submit"
onPress={handleSubmit}
disabled={true}
/>
Pressable Example
<Pressable
onPress={handleSubmit}
disabled={!isFormValid}
style={({ pressed }) => [
styles.button,
!isFormValid && styles.disabledButton,
pressed && isFormValid && styles.pressedButton
]}
>
<Text style={styles.buttonText}>Submit</Text>
</Pressable>
For a custom Pressable, the disabled style must be defined in your stylesheet. The disabled prop prevents the press interaction, while the style communicates the disabled state visually.
12. Creating a Reusable Custom Button
A reusable button allows developers to share a consistent design across the application. Instead of repeating the same Pressable markup on every screen, create a component that accepts props such as title, onPress, disabled, and variant.
Reusable Button Component
import React from 'react';
import {
Text,
Pressable,
StyleSheet
} from 'react-native';
export default function CustomButton({
title,
onPress,
disabled = false
}) {
return (
<Pressable
onPress={onPress}
disabled={disabled}
accessibilityRole="button"
accessibilityLabel={title}
style={({ pressed }) => [
styles.button,
disabled && styles.disabled,
pressed && !disabled && styles.pressed
]}
>
<Text style={styles.buttonText}>{title}</Text>
</Pressable>
);
}
const styles = StyleSheet.create({
button: {
backgroundColor: '#2563eb',
paddingVertical: 14,
paddingHorizontal: 22,
borderRadius: 8,
alignItems: 'center'
},
pressed: {
backgroundColor: '#1d4ed8'
},
disabled: {
backgroundColor: '#9ca3af'
},
buttonText: {
color: '#ffffff',
fontSize: 16,
fontWeight: 'bold'
}
});
Using the Reusable Component
import React from 'react';
import { View, Alert } from 'react-native';
import CustomButton from './CustomButton';
export default function App() {
return (
<View style={{ padding: 20 }}>
<CustomButton
title="Login"
onPress={() => Alert.alert('Login', 'Login selected')}
/>
<CustomButton
title="Continue"
disabled={true}
onPress={() => console.log('Continue')}
/>
</View>
);
}
Save the reusable component in a file such as CustomButton.js and import it wherever needed. Reusable components reduce duplication and make design changes easier to maintain.
13. What Are Touchable Components?
Touchable components are built-in React Native components that make child elements respond to touch. They are useful for creating custom buttons and interactive interface elements.
The most commonly used Touchable components include:
TouchableOpacity
TouchableHighlight
TouchableWithoutFeedback
TouchableNativeFeedback, which is primarily intended for Android-specific feedback.
For new custom interactions, React Native recommends considering Pressable because it offers flexible feedback and a more extensive set of press-state options. Touchable components remain useful in existing applications and for familiar interaction patterns.
14. Understanding TouchableOpacity
TouchableOpacity is a touchable component that reduces the opacity of its children while the user presses it. This creates a simple visual feedback effect.
It is commonly used for custom buttons, navigation items, image cards, and tappable text.
Basic Example
import React from 'react';
import {
View,
Text,
TouchableOpacity,
Alert,
StyleSheet
} from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.button}
activeOpacity={0.7}
onPress={() => Alert.alert('Success', 'TouchableOpacity pressed')}
>
<Text style={styles.buttonText}>Tap Here</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
button: {
backgroundColor: '#7c3aed',
paddingVertical: 14,
paddingHorizontal: 24,
borderRadius: 8
},
buttonText: {
color: '#ffffff',
fontSize: 16,
fontWeight: 'bold'
}
});
Understanding activeOpacity
The activeOpacity prop controls the opacity of the wrapped content during the active press. A lower value generally makes the content appear more transparent. The default value is 0.2.
<TouchableOpacity
activeOpacity={0.5}
onPress={handlePress}
>
<Text>Press Me</Text>
</TouchableOpacity>
Common Use Cases
- Buttons with custom designs.
- Clickable product images.
- Navigation links and menu items.
- Interactive profile cards.
- Custom list rows.
TouchableOpacity changes opacity to provide feedback. If you want to control several pressed-state styles, such as background color and scale, Pressable is often more flexible.
15. Understanding TouchableHighlight
TouchableHighlight provides touch feedback by showing an underlay color when the user presses the component. This can create a darkening or highlighting effect.
TouchableHighlight requires a single child element. If you want to include multiple elements, wrap them inside a View.
Example
import React from 'react';
import {
View,
Text,
TouchableHighlight,
Alert,
StyleSheet
} from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<TouchableHighlight
style={styles.button}
underlayColor="#1d4ed8"
activeOpacity={0.85}
onPress={() => Alert.alert('Pressed', 'Highlight button pressed')}
>
<Text style={styles.buttonText}>Highlight Button</Text>
</TouchableHighlight>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
button: {
backgroundColor: '#2563eb',
padding: 16,
borderRadius: 8
},
buttonText: {
color: '#ffffff',
fontWeight: 'bold'
}
});
Important Props
underlayColor: sets the color displayed behind the child during a press.
activeOpacity: controls the opacity of the wrapped content during the active press.
onPress: specifies the action performed when the press is recognized.
onShowUnderlay: runs when the underlay becomes visible.
onHideUnderlay: runs when the underlay is hidden.
Choose an underlay color that works with the child element's background. An unsuitable color or transparent styling may create unexpected visual effects.
16. Understanding TouchableWithoutFeedback
TouchableWithoutFeedback detects touch interactions without adding its own visual feedback. It is useful for specific interaction patterns where the interface should respond to a touch without changing its appearance.
It should be used carefully because users generally benefit from visible feedback when an element is interactive. It supports one child, so wrap multiple child elements inside a View.
Example
import React from 'react';
import {
View,
Text,
TouchableWithoutFeedback,
Alert,
StyleSheet
} from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<TouchableWithoutFeedback
onPress={() => Alert.alert('Selected', 'Area tapped')}
>
<View style={styles.box}>
<Text>Tap This Area</Text>
</View>
</TouchableWithoutFeedback>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
box: {
padding: 30,
backgroundColor: '#eeeeee',
borderRadius: 8
}
});
Common Use Cases
- Detecting touches on a background area.
- Implementing specific custom touch behavior.
- Handling touches where visual feedback is provided elsewhere.
For ordinary buttons, prefer a component that provides visible feedback and an appropriate accessibility role.
17. Understanding TouchableNativeFeedback
TouchableNativeFeedback is a React Native component primarily designed for Android-specific native touch feedback, such as ripple effects.
Its use is more platform-specific than Pressable or TouchableOpacity. For cross-platform applications, Pressable with its android_ripple property is often a convenient alternative when Android ripple feedback is desired.
Example Using Pressable Ripple Feedback
import React from 'react';
import {
View,
Text,
Pressable,
StyleSheet
} from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<Pressable
android_ripple={{ color: '#bfdbfe' }}
style={styles.button}
onPress={() => console.log('Ripple button pressed')}
>
<Text style={styles.buttonText}>Android Ripple Button</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 20
},
button: {
backgroundColor: '#2563eb',
padding: 16,
borderRadius: 8,
overflow: 'hidden'
},
buttonText: {
color: '#ffffff',
fontWeight: 'bold'
}
});
The ripple effect is platform-specific. Test it on Android and verify how the component looks on iOS, where Android ripple feedback is not displayed in the same way.
18. Comparing Pressable, Button, and Touchable Components
| Component |
Touch Feedback |
Styling Flexibility |
Best Use |
Pressable |
Configurable using pressed state, callbacks, and supported platform feedback. |
High |
Custom buttons, cards, list items, and complex interactions. |
Button |
Platform-rendered button feedback. |
Limited |
Simple actions that need minimal customization. |
TouchableOpacity |
Reduces opacity while pressed. |
High |
Custom buttons, links, and tappable content. |
TouchableHighlight |
Shows an underlay color. |
High |
Elements that benefit from a highlight effect. |
TouchableWithoutFeedback |
No built-in visual press feedback. |
High |
Special cases requiring touch detection without a visual effect. |
TouchableNativeFeedback |
Android-native feedback such as ripples. |
Platform-specific |
Existing Android-focused implementations. |
Which Component Should You Choose?
- Choose Pressable when you need a modern, customizable interaction with detailed press-state handling.
- Choose Button when a simple, platform-rendered action button is sufficient.
- Choose TouchableOpacity when opacity-based feedback fits your design.
- Choose TouchableHighlight when a visible underlay effect is desired.
- Choose TouchableWithoutFeedback only when its lack of built-in feedback is intentional.
- Choose TouchableNativeFeedback for existing Android-specific implementations where appropriate.
19. Managing Button State with useState
The useState hook allows a component to remember and update values. It is useful for interactive elements such as counters, favorite buttons, selection controls, and toggle actions.
Example: Counter Button
import React, { useState } from 'react';
import {
View,
Text,
Pressable,
StyleSheet
} from 'react-native';
export default function CounterApp() {
const [count, setCount] = useState(0);
return (
<View style={styles.container}>
<Text style={styles.count}>Count: {count}</Text>
<Pressable
style={styles.button}
onPress={() => setCount(previous => previous + 1)}
>
<Text style={styles.buttonText}>Increase Count</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
count: {
fontSize: 24,
marginBottom: 20
},
button: {
backgroundColor: '#16a34a',
padding: 16,
borderRadius: 8
},
buttonText: {
color: '#ffffff',
fontWeight: 'bold'
}
});
Each press updates the count. React then re-renders the component to display the new value. The functional updater form ensures that the new count is calculated from the previous state.
20. Building a Favorite Button
Favorite buttons are commonly used in shopping, travel, and social applications. A user can tap the button to mark or unmark an item as a favorite.
import React, { useState } from 'react';
import {
View,
Text,
Pressable,
StyleSheet
} from 'react-native';
export default function FavoriteButton() {
const [favorite, setFavorite] = useState(false);
return (
<View style={styles.container}>
<Pressable
onPress={() => setFavorite(previous => !previous)}
accessibilityRole="button"
accessibilityLabel={
favorite ? 'Remove from favorites' : 'Add to favorites'
}
style={styles.button}
>
<Text style={styles.buttonText}>
{favorite ? '♥ Added to Favorites' : '♡ Add to Favorites'}
</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 20
},
button: {
alignSelf: 'flex-start',
padding: 14,
backgroundColor: '#f3e8ff',
borderRadius: 8
},
buttonText: {
fontSize: 16,
color: '#6b21a8'
}
});
The state variable stores whether the item is a favorite. Pressing the button reverses the value and updates the label. In a real application, persistent favorites may also need to be saved to an API or local storage.
21. Creating a Loading Button
When a user submits a form or starts a network request, the application should provide feedback that the action is in progress. A loading button can prevent repeated submissions and communicate the current state.
import React, { useState } from 'react';
import {
View,
Text,
Pressable,
ActivityIndicator,
StyleSheet
} from 'react-native';
export default function LoadingButton() {
const [loading, setLoading] = useState(false);
const handleSubmit = async () => {
if (loading) return;
setLoading(true);
try {
await new Promise(resolve => setTimeout(resolve, 1500));
console.log('Operation completed');
} catch (error) {
console.error('Operation failed', error);
} finally {
setLoading(false);
}
};
return (
<View style={styles.container}>
<Pressable
onPress={handleSubmit}
disabled={loading}
accessibilityRole="button"
accessibilityState={{ disabled: loading, busy: loading }}
style={({ pressed }) => [
styles.button,
pressed && !loading && styles.pressed,
loading && styles.disabled
]}
>
{loading ? (
<View style={styles.row}>
<ActivityIndicator color="#ffffff" />
<Text style={styles.buttonText}>Please wait...</Text>
</View>
) : (
<Text style={styles.buttonText}>Submit</Text>
)}
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 20
},
button: {
padding: 16,
borderRadius: 8,
alignItems: 'center',
backgroundColor: '#2563eb'
},
pressed: {
backgroundColor: '#1d4ed8'
},
disabled: {
backgroundColor: '#93a3b8'
},
row: {
flexDirection: 'row',
alignItems: 'center',
gap: 10
},
buttonText: {
color: '#ffffff',
fontSize: 16,
fontWeight: 'bold'
}
});
The timeout in this example simulates an asynchronous operation for demonstration purposes. Replace it with your actual API request or business logic. The finally block resets the loading state whether the operation succeeds or fails.
22. Handling Form Submission with Pressable
Form submission is a common use case for interactive components. A button can validate user input before performing an action.
import React, { useState } from 'react';
import {
View,
Text,
TextInput,
Pressable,
Alert,
StyleSheet
} from 'react-native';
export default function LoginForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleLogin = () => {
if (!email.trim() || !password) {
Alert.alert('Validation Error', 'Enter your email and password.');
return;
}
Alert.alert('Login', 'Input validation passed.');
};
return (
<View style={styles.container}>
<Text style={styles.heading}>Login</Text>
<TextInput
value={email}
onChangeText={setEmail}
placeholder="Email address"
keyboardType="email-address"
autoCapitalize="none"
style={styles.input}
/>
<TextInput
value={password}
onChangeText={setPassword}
placeholder="Password"
secureTextEntry
style={styles.input}
/>
<Pressable style={styles.button} onPress={handleLogin}>
<Text style={styles.buttonText}>Login</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
justifyContent: 'center'
},
heading: {
fontSize: 28,
fontWeight: 'bold',
marginBottom: 20
},
input: {
borderWidth: 1,
borderColor: '#cccccc',
padding: 12,
borderRadius: 8,
marginBottom: 14
},
button: {
backgroundColor: '#2563eb',
padding: 15,
alignItems: 'center',
borderRadius: 8
},
buttonText: {
color: '#ffffff',
fontWeight: 'bold'
}
});
This example checks whether the fields are empty. Real authentication should also validate input appropriately and send credentials securely to a backend service. Never treat client-side validation alone as sufficient security.
23. Accessibility for Interactive Components
Accessibility ensures that interactive elements can be understood and used by people with different abilities. Buttons should have a clear purpose, an accessible name, and a state that can be communicated to accessibility services.
Useful Accessibility Props
accessibilityRole="button" identifies the element as a button.
accessibilityLabel describes the action or purpose of the element.
accessibilityHint can explain what happens when the element is activated.
accessibilityState can communicate states such as disabled or busy where supported.
disabled prevents the component's normal press action when unavailable.
Example
<Pressable
accessibilityRole="button"
accessibilityLabel="Save profile"
accessibilityHint="Saves the changes to your profile"
accessibilityState={{ disabled: false }}
onPress={handleSave}
>
<Text>Save</Text>
</Pressable>
Accessibility Best Practices
- Use descriptive labels rather than vague labels such as "Click here".
- Ensure the text is readable and has sufficient contrast.
- Provide feedback when an action succeeds or fails.
- Make the touch target large enough to be comfortably activated.
- Communicate disabled and busy states where appropriate.
- Test interactive elements with screen readers and on physical devices.
24. Common Mistakes and Troubleshooting
| Problem |
Possible Cause |
Solution |
| Button action runs immediately. |
The handler is called during rendering. |
Pass a function reference, such as onPress={handlePress}. |
| Pressable does not look like a button. |
Pressable does not supply a complete default button design. |
Add padding, background color, border radius, and text styling. |
| Button cannot be pressed. |
It may be disabled or covered by another element. |
Check the disabled prop, layout, and overlapping components. |
| TouchableHighlight shows an unexpected color. |
The underlay color conflicts with the child styling. |
Adjust underlayColor and the child's background. |
| TouchableOpacity looks too transparent. |
The activeOpacity value is too low. |
Increase activeOpacity to provide subtler feedback. |
| Long press does not trigger. |
The press duration is too short or the gesture is cancelled. |
Check onLongPress, delayLongPress, and touch handling. |
| Button can be submitted repeatedly. |
The action is not disabled while a request is running. |
Use loading state and disable the component during submission. |
| Button text is difficult to read. |
Insufficient contrast or unsuitable text styling. |
Adjust the foreground and background colors. |
| Accessibility tools announce an unclear action. |
The element has no meaningful accessible name. |
Add a descriptive accessibilityLabel and role. |
25. Best Practices for Using Touch Components
- Prefer Pressable for new custom interactive components that require flexible styling.
- Use Button for simple actions when its platform-rendered appearance is suitable.
- Choose TouchableOpacity or TouchableHighlight when their feedback styles fit the interface.
- Avoid TouchableWithoutFeedback for ordinary buttons unless the lack of feedback is intentional.
- Use clear event handler names, such as
handleSubmit and handleSave.
- Keep touch handlers focused on one responsibility.
- Disable buttons when actions are unavailable or already being processed.
- Show loading feedback for asynchronous operations.
- Use accessible labels and roles for interactive controls.
- Provide visible feedback for successful, failed, and unavailable actions.
- Test touch interactions on both Android and iOS.
- Prevent duplicate requests when a user taps repeatedly.
- Use reusable components to maintain consistent button design.
26. Practical Project: Interactive Action Menu
Project Objective: Create an action menu with custom Pressable buttons for viewing a profile, saving settings, and logging out.
Requirements
- Use Pressable to create custom buttons.
- Display a label for each action.
- Provide visual feedback when buttons are pressed.
- Use separate event handlers for each action.
- Include accessible button labels.
Complete Project Code
import React from 'react';
import {
View,
Text,
Pressable,
Alert,
StyleSheet
} from 'react-native';
export default function ActionMenu() {
const handleProfile = () => {
Alert.alert('Profile', 'Profile selected.');
};
const handleSettings = () => {
Alert.alert('Settings', 'Settings selected.');
};
const handleLogout = () => {
Alert.alert('Logout', 'Logout selected.');
};
return (
<View style={styles.container}>
<Text style={styles.heading}>Account Menu</Text>
<Pressable
style={({ pressed }) => [
styles.button,
pressed && styles.pressed
]}
onPress={handleProfile}
accessibilityRole="button"
accessibilityLabel="View profile"
>
<Text style={styles.buttonText}>View Profile</Text>
</Pressable>
<Pressable
style={({ pressed }) => [
styles.button,
pressed && styles.pressed
]}
onPress={handleSettings}
accessibilityRole="button"
accessibilityLabel="Open settings"
>
<Text style={styles.buttonText}>Settings</Text>
</Pressable>
<Pressable
style={({ pressed }) => [
styles.logoutButton,
pressed && styles.logoutPressed
]}
onPress={handleLogout}
accessibilityRole="button"
accessibilityLabel="Log out"
>
<Text style={styles.buttonText}>Logout</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
padding: 24,
backgroundColor: '#f8fafc'
},
heading: {
fontSize: 26,
fontWeight: 'bold',
marginBottom: 24,
textAlign: 'center'
},
button: {
backgroundColor: '#2563eb',
padding: 16,
borderRadius: 10,
alignItems: 'center',
marginBottom: 14
},
pressed: {
backgroundColor: '#1d4ed8'
},
logoutButton: {
backgroundColor: '#dc2626',
padding: 16,
borderRadius: 10,
alignItems: 'center'
},
logoutPressed: {
backgroundColor: '#991b1b'
},
buttonText: {
color: '#ffffff',
fontSize: 16,
fontWeight: 'bold'
}
});
Project Explanation
- View: Organizes the action menu layout.
- Text: Displays the heading and button labels.
- Pressable: Makes each action respond to user input.
- onPress: Connects each button to its corresponding handler.
- Dynamic style: Changes the button's background while it is pressed.
- Accessibility: Gives each button a meaningful role and label.
The example uses alerts to demonstrate interaction. In a production application, replace these handlers with navigation, settings updates, and a properly implemented logout workflow.
27. Practice Exercises
Beginner Exercises
- Create a Button that displays an alert when pressed.
- Create a custom Pressable button with a background color and rounded corners.
- Use TouchableOpacity to create a button with opacity feedback.
- Use TouchableHighlight with a custom underlay color.
- Create a disabled button and give it a different appearance.
Intermediate Exercises
- Build a counter using Pressable and useState.
- Create a favorite button that toggles between selected and unselected states.
- Implement a long-press action using Pressable.
- Build a reusable CustomButton component with title and onPress props.
- Create a loading button that prevents repeated submissions.
Advanced Exercises
- Build a login form with validation and a disabled submit button.
- Create a reusable button component with primary, secondary, and danger variants.
- Implement a custom pressed-state animation.
- Build an accessible action menu with different actions.
- Test touch interactions on Android and iOS and document any differences.
28. Interview Questions and Answers
Q1. What is Pressable in React Native?
Answer: Pressable is a built-in component that makes its children respond to touch interactions. It supports press callbacks, dynamic styling, long-press behavior, and other interaction options.
Q2. What is the Button component?
Answer: Button is a built-in component for creating simple platform-rendered buttons. It mainly uses the title and onPress props, with limited styling customization.
Q3. What is TouchableOpacity?
Answer: TouchableOpacity provides touch feedback by reducing the opacity of its children while they are pressed.
Q4. What is TouchableHighlight?
Answer: TouchableHighlight displays an underlay color during a press. It is useful when the desired feedback is a highlighted or darkened background.
Q5. What is TouchableWithoutFeedback?
Answer: TouchableWithoutFeedback detects touch interactions without providing its own visual press feedback. It should be used selectively.
Q6. What is the difference between Pressable and TouchableOpacity?
Answer: Pressable offers flexible press-state styling and several interaction callbacks. TouchableOpacity provides a simpler opacity-based feedback effect.
Q7. What is onPress?
Answer: onPress is a callback that runs when a press interaction is successfully recognized.
Q8. What is onLongPress?
Answer: onLongPress is a callback triggered when a user presses and holds an element long enough for the long-press gesture to be recognized.
Q9. What is the purpose of onPressIn?
Answer: onPressIn runs when the press interaction begins. It can be used to trigger early feedback or record the start of an interaction.
Q10. What is the purpose of onPressOut?
Answer: onPressOut runs when the press interaction ends, including situations where the interaction is cancelled.
Q11. How do you disable a Pressable component?
Answer: Set disabled={true}. A custom disabled style can also be applied to make the unavailable state visible.
Q12. How do you change a Pressable button's style when it is pressed?
Answer: Pass a function to the style prop and use its pressed state to return conditional styles.
Q13. Why create a reusable button component?
Answer: Reusable components reduce duplicated code, improve consistency, and make it easier to maintain button styling and behavior throughout an application.
Q14. How can you prevent multiple form submissions?
Answer: Track the loading state, disable the button while the request is running, and guard the event handler against duplicate calls.
Q15. Which component is suitable for a custom button?
Answer: Pressable is generally a good choice for a custom button because it supports flexible styling, press states, and interaction callbacks.
29. Quick Revision Checklist
- Understand the role of Pressable, Button, and Touchable components.
- Use onPress to handle a completed press.
- Use onPressIn and onPressOut to track press interactions.
- Use onLongPress to detect press-and-hold interactions.
- Use dynamic styles to provide pressed-state feedback.
- Use Button for simple actions with minimal customization.
- Use TouchableOpacity for opacity-based feedback.
- Use TouchableHighlight for underlay-based feedback.
- Use TouchableWithoutFeedback only when the lack of visual feedback is intentional.
- Use disabled and loading states to prevent unavailable or repeated actions.
- Create reusable button components for consistent design.
- Provide meaningful accessibility roles and labels.
- Test touch behavior on Android and iOS.
30. Conclusion
Pressable, Button, and Touchable components help developers build interactive React Native applications. Button is appropriate for simple actions, Pressable is flexible for custom controls, and Touchable components provide specific feedback styles such as opacity changes and underlay highlighting.
By understanding their props, event callbacks, disabled states, accessibility features, and styling options, developers can create reliable buttons, form actions, menus, counters, and reusable interface components.
Practice these concepts by creating a custom button library and using it in a login form, product list, and account menu. For further learning, visit the React Native Training course at JustAcademy or register for a course demo.
31. Additional Learning Resources