React Native Glow UI v1 is out now!
Logo
Components

Ripple

Ripple component for React Native.

Installation

npx rn-glow add ripple

🌊 TouchableRippleProps

PropTypeDefault
style?
StyleProp<ViewStyle>
-
borderRadius?
number
-
duration?
number
-
rippleColor?
string
-
onLongPress?
() => void
-
onPress?
() => void
-
children
React.ReactElement
-

🚀 Example

import { View, Text, StyleSheet, ScrollView, Alert } from "react-native";
import React from "react";
import {
  MaterialIcons,
  Feather,
  Ionicons,
  AntDesign,
} from "@expo/vector-icons";
import { TouchableRipple } from "@/components/index";
import { GestureHandlerRootView } from "react-native-gesture-handler";

const RippleDemo: React.FC = (): React.ReactNode => {
  const handlePress = (action: string) => {
    console.log(`${action} pressed`);
    Alert.alert("Action", `${action} was pressed!`);
  };

  const handleLongPress = (action: string) => {
    console.log(`${action} long pressed`);
    Alert.alert("Long Press", `${action} was long pressed!`);
  };

  return (
    <GestureHandlerRootView
      style={{
        flex: 1,
      }}
    >
      <ScrollView
        style={styles.container}
        contentContainerStyle={styles.content}
        scrollEnabled
        contentInsetAdjustmentBehavior="always"
        showsVerticalScrollIndicator={false}
      >
        <View style={styles.header}>
          <View style={styles.iconContainer}>
            <MaterialIcons name="touch-app" size={32} color="#60a5fa" />
          </View>
          <Text style={styles.title}>TouchableRipple Demo</Text>
          <Text style={styles.subtitle}>
            Interactive ripple effects with beautiful animations
          </Text>
        </View>

        <View style={styles.section}>
          <Text style={styles.sectionTitle}>Basic Buttons</Text>

          <View style={styles.buttonRow}>
            <TouchableRipple
              borderRadius={8}
              onPress={() => handlePress("Primary Button")}
              duration={300}
              rippleColor="rgba(96, 165, 250, 0.3)"
              onLongPress={() => handleLongPress("Primary Button")}
              style={styles.primaryButton}
            >
              <View style={styles.buttonContent}>
                <Feather name="zap" size={18} color="#fafafa" />
                <Text style={styles.primaryButtonText}>Primary</Text>
              </View>
            </TouchableRipple>

            <TouchableRipple
              borderRadius={8}
              onPress={() => handlePress("Secondary Button")}
              duration={300}
              rippleColor="rgba(161, 161, 170, 0.3)"
              onLongPress={() => handleLongPress("Secondary Button")}
              style={styles.secondaryButton}
            >
              <View style={styles.buttonContent}>
                <Feather name="settings" size={18} color="#a1a1aa" />
                <Text style={styles.secondaryButtonText}>Secondary</Text>
              </View>
            </TouchableRipple>
          </View>
        </View>

        <View style={styles.section}>
          <Text style={styles.sectionTitle}>Action Cards</Text>

          <TouchableRipple
            borderRadius={12}
            onPress={() => handlePress("Profile Card")}
            duration={400}
            rippleColor="rgba(16, 185, 129, 0.2)"
            onLongPress={() => handleLongPress("Profile Card")}
            style={styles.card}
          >
            <View style={styles.cardContent}>
              <View style={styles.cardIcon}>
                <Feather name="user" size={24} color="#10b981" />
              </View>
              <View style={styles.cardText}>
                <Text style={styles.cardTitle}>Profile Settings</Text>
                <Text style={styles.cardDescription}>
                  Manage your account and preferences
                </Text>
              </View>
              <MaterialIcons
                name="arrow-forward-ios"
                size={16}
                color="#71717a"
              />
            </View>
          </TouchableRipple>

          <TouchableRipple
            borderRadius={12}
            onPress={() => handlePress("Notifications Card")}
            duration={400}
            rippleColor="rgba(245, 158, 11, 0.2)"
            onLongPress={() => handleLongPress("Notifications Card")}
            style={styles.card}
          >
            <View style={styles.cardContent}>
              <View style={styles.cardIcon}>
                <Ionicons
                  name="notifications-outline"
                  size={24}
                  color="#f59e0b"
                />
              </View>
              <View style={styles.cardText}>
                <Text style={styles.cardTitle}>Notifications</Text>
                <Text style={styles.cardDescription}>
                  Configure your notification preferences
                </Text>
              </View>
              <MaterialIcons
                name="arrow-forward-ios"
                size={16}
                color="#71717a"
              />
            </View>
          </TouchableRipple>

          <TouchableRipple
            borderRadius={12}
            onPress={() => handlePress("Security Card")}
            duration={400}
            rippleColor="rgba(239, 68, 68, 0.2)"
            onLongPress={() => handleLongPress("Security Card")}
            style={styles.card}
          >
            <View style={styles.cardContent}>
              <View style={styles.cardIcon}>
                <Feather name="shield" size={24} color="#ef4444" />
              </View>
              <View style={styles.cardText}>
                <Text style={styles.cardTitle}>Security</Text>
                <Text style={styles.cardDescription}>
                  Privacy and security settings
                </Text>
              </View>
              <MaterialIcons
                name="arrow-forward-ios"
                size={16}
                color="#71717a"
              />
            </View>
          </TouchableRipple>
        </View>

        <View style={styles.section}>
          <Text style={styles.sectionTitle}>Icon Buttons</Text>

          <View style={styles.iconButtonRow}>
            <TouchableRipple
              borderRadius={24}
              onPress={() => handlePress("Like")}
              duration={250}
              rippleColor="rgba(239, 68, 68, 0.4)"
              onLongPress={() => handleLongPress("Like")}
              style={styles.iconButton}
            >
              <AntDesign name="heart" size={20} color="#ef4444" />
            </TouchableRipple>

            <TouchableRipple
              borderRadius={24}
              onPress={() => handlePress("Share")}
              duration={250}
              rippleColor="rgba(96, 165, 250, 0.4)"
              onLongPress={() => handleLongPress("Share")}
              style={styles.iconButton}
            >
              <Feather name="share-2" size={20} color="#60a5fa" />
            </TouchableRipple>

            <TouchableRipple
              borderRadius={24}
              onPress={() => handlePress("Bookmark")}
              duration={250}
              rippleColor="rgba(245, 158, 11, 0.4)"
              onLongPress={() => handleLongPress("Bookmark")}
              style={styles.iconButton}
            >
              <Feather name="bookmark" size={20} color="#f59e0b" />
            </TouchableRipple>

            <TouchableRipple
              borderRadius={24}
              onPress={() => handlePress("More")}
              duration={250}
              rippleColor="rgba(139, 92, 246, 0.4)"
              onLongPress={() => handleLongPress("More")}
              style={styles.iconButton}
            >
              <Feather name="more-horizontal" size={20} color="#8b5cf6" />
            </TouchableRipple>
          </View>
        </View>

        <View style={styles.section}>
          <Text style={styles.sectionTitle}>Floating Action Button</Text>

          <View style={styles.fabContainer}>
            <TouchableRipple
              borderRadius={28}
              onPress={() => handlePress("Add New Item")}
              duration={300}
              rippleColor="rgba(255, 255, 255, 0.3)"
              onLongPress={() => handleLongPress("Add New Item")}
              style={styles.fab}
            >
              <Feather name="plus" size={24} color="#fafafa" />
            </TouchableRipple>
          </View>
        </View>

        <View style={styles.footer}>
          <View style={styles.footerIcon}>
            <Feather name="info" size={16} color="#71717a" />
          </View>
          <Text style={styles.footerText}>
            Try tapping and long-pressing the buttons to see different ripple
            effects
          </Text>
        </View>
      </ScrollView>
    </GestureHandlerRootView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#09090b",
  },
  content: {
    padding: 24,
    paddingBottom: 48,
  },
  header: {
    alignItems: "center",
    marginBottom: 32,
    paddingTop: 20,
  },
  iconContainer: {
    width: 64,
    height: 64,
    borderRadius: 32,
    backgroundColor: "#18181b",
    alignItems: "center",
    justifyContent: "center",
    marginBottom: 16,
    borderWidth: 1,
    borderColor: "#27272a",
  },
  title: {
    fontSize: 28,
    fontWeight: "700",
    color: "#fafafa",
    marginBottom: 8,
    textAlign: "center",
  },
  subtitle: {
    fontSize: 16,
    color: "#a1a1aa",
    textAlign: "center",
    lineHeight: 24,
    maxWidth: 320,
  },
  section: {
    marginBottom: 32,
  },
  sectionTitle: {
    fontSize: 18,
    fontWeight: "600",
    color: "#e4e4e7",
    marginBottom: 16,
    marginLeft: 4,
  },
  buttonRow: {
    flexDirection: "row",
    gap: 12,
  },
  primaryButton: {
    flex: 1,
    backgroundColor: "#2563eb",
    paddingVertical: 12,
    paddingHorizontal: 20,
  },
  secondaryButton: {
    flex: 1,
    backgroundColor: "#18181b",
    borderWidth: 1,
    borderColor: "#27272a",
    paddingVertical: 12,
    paddingHorizontal: 20,
  },
  buttonContent: {
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "center",
    gap: 8,
  },
  primaryButtonText: {
    color: "#fafafa",
    fontSize: 16,
    fontWeight: "600",
  },
  secondaryButtonText: {
    color: "#a1a1aa",
    fontSize: 16,
    fontWeight: "600",
  },
  card: {
    backgroundColor: "#18181b",
    borderWidth: 1,
    borderColor: "#27272a",
    marginBottom: 12,
  },
  cardContent: {
    flexDirection: "row",
    alignItems: "center",
    padding: 16,
  },
  cardIcon: {
    width: 48,
    height: 48,
    borderRadius: 24,
    backgroundColor: "#09090b",
    alignItems: "center",
    justifyContent: "center",
    marginRight: 16,
  },
  cardText: {
    flex: 1,
  },
  cardTitle: {
    fontSize: 16,
    fontWeight: "600",
    color: "#fafafa",
    marginBottom: 4,
  },
  cardDescription: {
    fontSize: 14,
    color: "#a1a1aa",
    lineHeight: 20,
  },
  iconButtonRow: {
    flexDirection: "row",
    justifyContent: "space-around",
    gap: 16,
  },
  iconButton: {
    width: 48,
    height: 48,
    backgroundColor: "#18181b",
    borderWidth: 1,
    borderColor: "#27272a",
    alignItems: "center",
    justifyContent: "center",
  },
  fabContainer: {
    alignItems: "center",
  },
  fab: {
    width: 56,
    height: 56,
    backgroundColor: "#2563eb",
    alignItems: "center",
    justifyContent: "center",
    elevation: 8,
    shadowColor: "#000",
    shadowOffset: {
      width: 0,
      height: 4,
    },
    shadowOpacity: 0.3,
    shadowRadius: 8,
  },
  footer: {
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "center",
    marginTop: 16,
    padding: 16,
    backgroundColor: "#18181b",
    borderRadius: 8,
    borderWidth: 1,
    borderColor: "#27272a",
  },
  footerIcon: {
    marginRight: 8,
  },
  footerText: {
    fontSize: 14,
    color: "#a1a1aa",
    textAlign: "center",
    flex: 1,
    lineHeight: 20,
  },
});

export default RippleDemo;