TouchableRipple
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> ); }
| Prop | Type | Default | Description |
|---|---|---|---|
onPress | (((event: GestureResponderEvent) => void) & ((e: GestureResponderEvent) => void)) | undefined | — | Function to execute on press. If not set, will cause the touchable to be disabled. |
onLongPress | (((event: GestureResponderEvent) => void) & ((e: GestureResponderEvent) => void)) | undefined | — | Function 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 | undefined | — | Content of the `TouchableRipple`. |
disabled | boolean | undefined | — | Whether 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 | — | — |
borderless | boolean | undefined | — | Whether to render the ripple outside the view bounds. |
background | Object | undefined | — | Type of background drawabale to display the feedback (Android). https://reactnative.dev/docs/touchablenativefeedback#background |
centered | boolean | undefined | — | Whether to start the ripple at the center (Web). |
rippleColor | string | undefined | — | Color of the ripple effect (Android >= 5.0 and Web). |
underlayColor | string | undefined | — | Color of the underlay for the highlight effect (Android < 5.0 and iOS). |
asChild | boolean | undefined | — | When `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. |