Fade Text
Word by word fade-in text animation with smooth blur
Last updated on
Manual
Install the following dependencies:
npm install react-native-reanimated expo-blurCopy and paste the following code into your project.
component/organisms/fade-text
import { BlurView, type BlurViewProps } from "expo-blur";import React, { memo, useEffect } from "react";import { StyleSheet, Text, View, type ViewStyle } from "react-native";import Animated, { Easing, Extrapolation, interpolate, useAnimatedProps, useAnimatedStyle, useSharedValue, withDelay, withSpring, withTiming,} from "react-native-reanimated";import type { AnimatedWordProps, FadeTextProps } from "./types";const AnimatedBlurView = Animated.createAnimatedComponent<BlurViewProps>(BlurView);export const FadeText: React.FC<FadeTextProps> = memo<FadeTextProps>( ({ inputs, wordDelay = 300, duration = 800, blurIntensity = [30, 10, 0], blurTint = "dark", scaleRange = [0.97, 1], translateYRange = [10, 0], opacityRange = [0, 0.5, 1], fontSize = 32, fontWeight = "600", color = "#ffffff", textAlign = "center", containerStyle, style, }: FadeTextProps): React.ReactNode & React.JSX.Element => { const words = inputs.flatMap((text, inputIndex) => text.split(" ").map((word) => ({ word, inputIndex })), ); return ( <View style={[styles.container, containerStyle]}> <View style={styles.textWrapper}> {words.map((item, index) => ( <AnimatedWord key={index} word={item.word} index={index} delay={index * wordDelay} duration={duration} blurIntensity={blurIntensity} blurTint={blurTint} scaleRange={scaleRange} translateYRange={translateYRange} opacityRange={opacityRange} fontSize={fontSize} style={style} fontWeight={fontWeight} color={color} textAlign={textAlign} /> ))} </View> </View> ); },);const AnimatedWord: React.FC<AnimatedWordProps> = memo<AnimatedWordProps>( ({ word, delay, duration, blurIntensity, blurTint, scaleRange, translateYRange, opacityRange, fontSize, fontWeight, color, textAlign, style, }: AnimatedWordProps): React.ReactNode & React.JSX.Element => { const animationValue = useSharedValue<number>(0); useEffect(() => { animationValue.value = withDelay( delay, withTiming<number>(1, { duration, easing: Easing.out(Easing.cubic), }), ); }, [delay, duration]); const animatedStyle = useAnimatedStyle< Pick<ViewStyle, "opacity" | "transform"> >(() => { const opacity = interpolate( animationValue.value, [0, 0.8, 1], opacityRange, Extrapolation.CLAMP, ); const scale = interpolate( animationValue.value, [0, 1], scaleRange, Extrapolation.CLAMP, ); const translateY = interpolate( animationValue.value, [0, 1], translateYRange, Extrapolation.CLAMP, ); return { opacity, transform: [{ scale }, { translateY }], }; }); const blurAnimatedProps = useAnimatedProps< Pick<BlurViewProps, "intensity"> >(() => { const intensity = withSpring<number>( interpolate( animationValue.value, [0, 0.3, 1], blurIntensity, Extrapolation.CLAMP, ), ); return { intensity, }; }); return ( <Animated.View style={[styles.wordContainer, animatedStyle]}> <Text style={[ styles.word, { fontSize, fontWeight, color, textAlign, }, style, ]} > {word}{" "} </Text> <AnimatedBlurView style={[StyleSheet.absoluteFillObject]} animatedProps={blurAnimatedProps} tint={blurTint} /> </Animated.View> ); },);const styles = StyleSheet.create({ container: { justifyContent: "center", alignItems: "center", paddingHorizontal: 20, }, textWrapper: { flexDirection: "row", flexWrap: "wrap", justifyContent: "center", alignItems: "center", }, wordContainer: { overflow: "hidden", borderRadius: 4, }, word: {},});Usage
import { View, Text, StyleSheet } from "react-native";import { GestureHandlerRootView } from "react-native-gesture-handler";import { StatusBar } from "expo-status-bar";import { Ionicons } from "@expo/vector-icons";import Dropdown from "@/components/organisms/dropdown";import { useFonts } from "expo-font";import EnergyOrb from "@/components/organisms/energy-orb";import { FadeText } from "@/components/organisms/fade-text";export default function App(): React.JSX.Element { const [fontLoaded] = useFonts({ SfProRounded: require("@/assets/fonts/sf-pro-rounded.ttf"), HelveticaNowDisplay: require("@/assets/fonts/HelveticaNowDisplayMedium.ttf"), Coolvetica: require("@/assets/fonts/Coolvetica-Rg.otf"), }); const INPUTS: string[] = [ "Reacticx is awesome!", "UI components made easy.", "Build stunning apps fast.", "Customizable and flexible.", "Join the Reacticx community!", ]; return ( <GestureHandlerRootView style={styles.container}> <StatusBar style="light" /> <View style={{ justifyContent: "center", alignItems: "center", marginTop: 100, }} > <FadeText inputs={INPUTS} duration={3500} wordDelay={300} blurTint="extraLight" style={{ fontFamily: fontLoaded ? "SfProRounded" : undefined, }} /> </View> </GestureHandlerRootView> );}const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#000", paddingHorizontal: 24, }, card: { backgroundColor: "rgba(255,255,255,0.08)", borderRadius: 20, padding: 20, top: 120, }, header: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", }, title: { color: "#fff", fontSize: 17, fontWeight: "600", }, subtitle: { color: "rgba(255,255,255,0.6)", fontSize: 13, marginTop: 2, }, body: { marginTop: 12, color: "rgba(255,255,255,0.75)", fontSize: 14, lineHeight: 20, }, trigger: { width: 36, height: 36, borderRadius: 10, backgroundColor: "rgba(255,255,255,0.12)", justifyContent: "center", alignItems: "center", }, menu: { backgroundColor: "#fff", }, itemText: { fontSize: 15, color: "#111", }, destructive: { color: "#dc2626", },});Props
React Native Reanimated
Expo Blur
