Fade Text

Word by word fade-in text animation with smooth blur

Last updated on

Edit on GitHub

Manual

Install the following dependencies:

npm install react-native-reanimated expo-blur

Copy 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