Skip to main content

TouchableRipple

Utilities

TouchableRipple

Pressable wrapper providing ripple feedback consistent with Material 3.

Usage

Wrap any interactive surface to align press visuals with the design system.

Highlights

  • Supports bordered and borderless modes
  • Integrates with StateLayer when hovered

When to use it

  • Custom components require Material ripple animations.
  • Need to match RN Paper/Material motion without extra deps.

Examples

Default

Preview (Web)
import { StyleSheet, View } from 'react-native';
import { TouchableRipple } from 'react-native-molecules/components/TouchableRipple';
import { Text } from 'react-native-molecules/components/Text';

const styles = StyleSheet.create({
container: {
width: 220,
height: 120,
borderRadius: 16,
alignItems: 'center',
justifyContent: 'center',
},
});

export default function Example() {
  return (
      <View style={{ gap: 12 }}>
          <TouchableRipple style={styles.container} onPress={() => console.log('Pressed')}>
              <Text>Touchable Ripple</Text>
          </TouchableRipple>
      </View>
  );
}

asChild

When asChild is true, TouchableRipple won't render a wrapper element. Instead, it merges its props (styles, event handlers, ref) onto its immediate child element. This follows the Radix UI "Slot" pattern for flexible component composition.

note

When using asChild, only a single child element is allowed. On native Android, the ripple effect won't work with asChild since TouchableNativeFeedback requires a View wrapper.

Preview (Web)
import { StyleSheet, View } from 'react-native';
import { TouchableRipple } from 'react-native-molecules/components/TouchableRipple';
import { Text } from 'react-native-molecules/components/Text';
import { Surface } from 'react-native-molecules/components/Surface';

const styles = StyleSheet.create({
card: {
width: 220,
height: 120,
borderRadius: 16,
alignItems: 'center',
justifyContent: 'center',
},
});

export default function Example() {
  return (
      <TouchableRipple asChild onPress={() => console.log('Pressed')}>
          <Surface style={styles.card} elevation={2}>
              <Text>Pressable Surface (asChild)</Text>
          </Surface>
      </TouchableRipple>
  );
}
PropTypeDefaultDescription
onPress(((event: GestureResponderEvent) => void) & ((e: GestureResponderEvent) => void)) | undefinedFunction to execute on press. If not set, will cause the touchable to be disabled.
onLongPress(((event: GestureResponderEvent) => void) & ((e: GestureResponderEvent) => void)) | undefinedFunction to execute on long press.
children((string | number | bigint | boolean | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<string | number | bigint | boolean | ReactPortal | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | ((state: PressableStateCallbackType) => React.ReactNode)) & (string | number | bigint | boolean | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<string | number | bigint | boolean | ReactPortal | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined>)) | null | undefinedContent of the `TouchableRipple`.
disabledboolean | undefinedWhether to prevent interaction with the touchable.
style((false | "" | ViewStyle | RegisteredStyle<ViewStyle> | RecursiveArray<Falsy | ViewStyle | RegisteredStyle<ViewStyle>> | ((state: PressableStateCallbackType) => StyleProp<ViewStyle>)) & (false | "" | ViewStyle | RegisteredStyle<ViewStyle> | RecursiveArray<Falsy | ViewStyle | RegisteredStyle<ViewStyle>>)) | null | undefined
borderlessboolean | undefinedWhether to render the ripple outside the view bounds.
backgroundObject | undefinedType of background drawabale to display the feedback (Android). https://reactnative.dev/docs/touchablenativefeedback#background
centeredboolean | undefinedWhether to start the ripple at the center (Web).
rippleColorstring | undefinedColor of the ripple effect (Android >= 5.0 and Web).
underlayColorstring | undefinedColor of the underlay for the highlight effect (Android < 5.0 and iOS).
asChildboolean | undefinedWhen `true`, the component will not render a wrapper element. Instead, it will merge its props (styles, event handlers, ref) onto its immediate child element. This follows the Radix UI "Slot" pattern for flexible component composition.
Defined in react-native-molecules/components/TouchableRipple