Skip to main content
Do not use unless you have a very good reason. All elements that respond to press should have visual feedback when touched. This is one of the primary reasons a “web” app doesn’t feel “native”.
TouchableWithoutFeedback handles touch interactions but provides no visual feedback to the user. It should only be used in specific cases where you’re implementing custom visual feedback.

Usage

import { TouchableWithoutFeedback, View, Text, StyleSheet } from 'react-native';

function App() {
  return (
    <TouchableWithoutFeedback onPress={() => console.log('Pressed')}>
      <View style={styles.container}>
        <Text>Touch me (no visual feedback)</Text>
      </View>
    </TouchableWithoutFeedback>
  );
}

const styles = StyleSheet.create({
  container: {
    padding: 20,
    backgroundColor: '#f0f0f0',
  },
});
TouchableWithoutFeedback must have exactly one child. Use a View to wrap multiple children.

Props

onPress
(event: GestureResponderEvent) => void
Called when the touch is released, but not if cancelled (e.g., by a scroll that steals the responder lock).
onPressIn
(event: GestureResponderEvent) => void
Called when a touch is engaged, immediately when the finger touches down.
onPressOut
(event: GestureResponderEvent) => void
Called when the touch is released or cancelled.
onLongPress
(event: GestureResponderEvent) => void
Called when the user holds down the press for more than delayLongPress milliseconds.
disabled
boolean
default:"false"
If true, disables all interactions for this component.
delayPressIn
number
default:"0"
Delay in milliseconds from the start of the touch before onPressIn is called.
delayPressOut
number
default:"0"
Delay in milliseconds from the release of the touch before onPressOut is called.
delayLongPress
number
default:"500"
Delay in milliseconds from onPressIn before onLongPress is called.
hitSlop
Insets
Extends the touchable area without changing visual layout.
<TouchableWithoutFeedback
  hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
  onPress={handlePress}
>
  <View><Text>Easier to tap</Text></View>
</TouchableWithoutFeedback>
pressRetentionOffset
Insets
Defines how far the touch can move off the button before deactivating it.
touchSoundDisabled
boolean
If true, doesn’t play system sound on touch.
testID
string
Used to locate this view in end-to-end tests.
TouchableWithoutFeedback also supports accessibility props.

When to Use

Custom Feedback Implementation

When you need to implement custom visual feedback:
function CustomButton() {
  const [pressed, setPressed] = React.useState(false);
  
  return (
    <TouchableWithoutFeedback
      onPressIn={() => setPressed(true)}
      onPressOut={() => setPressed(false)}
    >
      <View style={[
        styles.button,
        pressed && styles.buttonPressed,
      ]}>
        <Text>Custom Feedback</Text>
      </View>
    </TouchableWithoutFeedback>
  );
}

const styles = StyleSheet.create({
  button: {
    padding: 20,
    backgroundColor: '#007AFF',
  },
  buttonPressed: {
    transform: [{ scale: 0.95 }],
    backgroundColor: '#0051D5',
  },
});

Dismissing Overlays

For closing modals or dropdowns when tapping outside:
function Modal({ visible, onClose, children }) {
  return (
    <View style={styles.overlay}>
      <TouchableWithoutFeedback onPress={onClose}>
        <View style={styles.backdrop} />
      </TouchableWithoutFeedback>
      <View style={styles.content}>
        {children}
      </View>
    </View>
  );
}

Keyboard Dismissal

Wrapping content to dismiss keyboard when tapping:
import { Keyboard } from 'react-native';

function FormScreen() {
  return (
    <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
      <View style={styles.container}>
        <TextInput placeholder="Username" />
        <TextInput placeholder="Password" secureTextEntry />
        <Button title="Login" onPress={handleLogin} />
      </View>
    </TouchableWithoutFeedback>
  );
}

Common Patterns

Image with Custom Overlay

function ImageCard({ source, onPress }) {
  const [pressed, setPressed] = React.useState(false);
  
  return (
    <TouchableWithoutFeedback
      onPressIn={() => setPressed(true)}
      onPressOut={() => setPressed(false)}
      onPress={onPress}
    >
      <View>
        <Image source={source} style={styles.image} />
        {pressed && (
          <View style={styles.overlay}>
            <Icon name="play" size={48} color="white" />
          </View>
        )}
      </View>
    </TouchableWithoutFeedback>
  );
}

Animated Custom Feedback

function AnimatedButton({ onPress, children }) {
  const scaleAnim = useRef(new Animated.Value(1)).current;
  
  const handlePressIn = () => {
    Animated.spring(scaleAnim, {
      toValue: 0.95,
      useNativeDriver: true,
    }).start();
  };
  
  const handlePressOut = () => {
    Animated.spring(scaleAnim, {
      toValue: 1,
      useNativeDriver: true,
    }).start();
  };
  
  return (
    <TouchableWithoutFeedback
      onPressIn={handlePressIn}
      onPressOut={handlePressOut}
      onPress={onPress}
    >
      <Animated.View style={{ transform: [{ scale: scaleAnim }] }}>
        {children}
      </Animated.View>
    </TouchableWithoutFeedback>
  );
}

Why You Should Avoid It

TouchableWithoutFeedback lacks visual feedback, which:
  1. Reduces user confidence - users don’t know if their tap registered
  2. Makes the app feel unresponsive and “web-like”
  3. Violates platform design guidelines (iOS and Android)
  4. Decreases accessibility for users with motor impairments

Better Alternatives

Use TouchableOpacity

// Instead of:
<TouchableWithoutFeedback onPress={handlePress}>
  <View><Text>Press Me</Text></View>
</TouchableWithoutFeedback>

// Use:
<TouchableOpacity onPress={handlePress}>
  <Text>Press Me</Text>
</TouchableOpacity>

Use Pressable

For more control with proper feedback:
<Pressable
  onPress={handlePress}
  style={({ pressed }) => [
    styles.button,
    pressed && styles.pressed,
  ]}
>
  {({ pressed }) => (
    <Text style={pressed && { opacity: 0.7 }}>
      Press Me
    </Text>
  )}
</Pressable>

Use TouchableHighlight

For underlay color feedback:
<TouchableHighlight
  onPress={handlePress}
  underlayColor="#DDDDDD"
>
  <View><Text>Press Me</Text></View>
</TouchableHighlight>

Accessibility Considerations

If you must use TouchableWithoutFeedback, ensure proper accessibility:
<TouchableWithoutFeedback
  accessible={true}
  accessibilityRole="button"
  accessibilityLabel="Submit form"
  accessibilityHint="Submits the registration form"
  onPress={handleSubmit}
>
  <View style={styles.customButton}>
    <Text>Submit</Text>
  </View>
</TouchableWithoutFeedback>

Limitations

  • Must have exactly one child (wrap multiple children in a View)
  • No built-in visual feedback
  • Child must be a native component (View, Text, Image, etc.)
  • Cannot use with functional components directly

Build docs developers (and LLMs) love