DEV Community

Cover image for Stop Making Boring UIs: Advanced React Native Animations with Reanimated
Saloni Agrawal
Saloni Agrawal

Posted on

Stop Making Boring UIs: Advanced React Native Animations with Reanimated

Modern apps rely on motion to guide attention, signal state changes, and make interactions feel naturally connected.

This part will deep dive into real-world patterns used inside popular mobile apps.

This includes:

  • Text transitions (single-word cycling, staggered lines)
  • Gesture animations (drag, swipe-to-dismiss)
  • Sequencing (delays, chained animations)
  • A combined onboarding example
  • Performance rules that actually matter

1. Text Animations in React Native

Text is one of the most expressive elements in any interface.
With animation, even a single line can set tone, build anticipation, or pace the user’s reading experience.

Seen commonly in:

  • Notion’s rotating value statements
  • Headspace and Calm onboarding
  • Airbnb’s welcoming slides
  • Slack’s product hero screens

Below are two foundational text animation patterns.

1.1 Cycling Words (Slide + Fade)

A rotating headline allows an app to communicate multiple ideas without overwhelming the layout.
Each word appears with a soft fade and lift, maintaining clarity and visual interest.

Used heavily by Notion, Slack, Duolingo, and similar modern apps.

const WordCycle = ({
  words = ["Design", "Build", "Ship"],
}) => {
  const [index, setIndex] = useState(0);
  const anim = useSharedValue(1);

  const cycle = () => {
    anim.value = withTiming(0, { duration: 180 }, () => {
      runOnJS(setIndex)((index + 1) % words.length);
      anim.value = withTiming(1, { duration: 350 });
    });
  };

  const style = useAnimatedStyle(() => ({
    opacity: anim.value,
    transform: [{ translateY: (1 - anim.value) * 10 }],
  }));

  return (
    <View style={{ alignItems: "center" }}>
      <Animated.Text style={[styles.word, style]}>
        {words[index]}
      </Animated.Text>

      <Pressable style={styles.triggerBtn} onPress={cycle}>
        <Text style={styles.triggerText}>Next Word</Text>
      </Pressable>
    </View>
  );
};
Enter fullscreen mode Exit fullscreen mode

Cyclic Texts GIF

Why this matters

The fade-out → swap → fade-in sequence keeps the transition soft.
It mirrors how a narrator would switch topics: gracefully, not abruptly.

📝 A Quick Note on runOnJS

If you noticed runOnJS(setIndex) inside the word cycling animation and wondered why it's needed, here’s the simple reason:
Reanimated runs its animations on the UI thread, not the JavaScript thread.

But React state updates (like setIndex) only work in JavaScript.
Since you can’t call React state directly from a UI-thread worklet, runOnJS acts as the safe bridge.

anim.value = withTiming(0, { duration: 180 }, () => {
  runOnJS(setIndex)((index + 1) % words.length);
  anim.value = withTiming(1, { duration: 350 });
});

1.2 Staggered Multi-line Text

Staggered text reveals information line-by-line, establishing pacing.
This pattern is so effective that apps like Airbnb, Calm, and Spotify rely on it constantly.

Staggering creates a natural reading sequence — a simple but powerful storytelling device.

const StaggeredLine = ({ text, index }) => {
  const anim = useSharedValue(0);

  const reveal = () => {
    anim.value = withDelay(index * 120, withTiming(1, { duration: 350 }));
  };

  const style = useAnimatedStyle(() => ({
    opacity: anim.value,
    transform: [{ translateY: (1 - anim.value) * 10 }],
  }));

  return (
    <View>
      <Animated.Text style={[styles.staggerText, style]}>
        {text}
      </Animated.Text>

      {index === 0 && (
        <Pressable style={styles.triggerBtn} onPress={reveal}>
          <Text style={styles.triggerText}>Reveal Text</Text>
        </Pressable>
      )}
    </View>
  );
};
Enter fullscreen mode Exit fullscreen mode

Staggered Multi-line Text GIF

Why this works

Staggering creates hierarchy and guides attention intentionally — line → pause → line → pause.

This instantly gives your UI that “premium onboarding” feel.


2. Micro-Interaction: The CTA Button Animation

A button may look simple, but it’s one of the most emotionally sensitive elements in UI.
When it responds instantly and physically, users feel the interaction was registered.

This pattern appears in Instagram, YouTube, Cash App, and nearly every major product.

const AnimatedButton = () => {
  const scale = useSharedValue(1);

  const animate = () => {
    scale.value = withSequence(
      withTiming(0.9, { duration: 120 }),
      withSpring(1)
    );
  };

  const style = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  return (
    <Animated.View style={style}>
      <Pressable style={styles.cta} onPress={animate}>
        <Text style={styles.ctaText}>Get Started</Text>
      </Pressable>
    </Animated.View>
  );
};
Enter fullscreen mode Exit fullscreen mode

Micro Interactions GIF

Why this matters

  • The 0.9 scale gives the sense of a real button press
  • The spring back makes the button feel responsive and alive
  • This tactile micro-interaction creates trust and momentum

It’s not decorative — it’s feedback.


3. Bringing It All Together: A Complete Onboarding Screen

export default function App() {
  return (
    <SafeAreaView style={styles.container}>
      <WordCycle words={["Design", "Build", "Ship"]} />

      <StaggeredText lines={["Welcome", "Let’s build something great"]} />

      <AnimatedButton />
    </SafeAreaView>
  );
}
Enter fullscreen mode Exit fullscreen mode

This layout mirrors the emotional arc used in onboarding for Calm, Duolingo, Headspace, and other thoughtfully designed apps.

  • The headline shifts gently
  • The message unfolds with clarity
  • The button reacts with personality

This creates a beginning → middle → call-to-action story.


4. Performance Choices That Actually Matter

Prefer transforms over layout changes

Transform animations (translate, scale, opacity) stay on the GPU.
Layout animations force recalculation, making them stutter on mid-range devices.

Keep Android shadows subtle

Android recalculates shadows on every frame.
Heavy shadows cause jank during animations.

Test on mid-range Android hardware

90% of animation bugs never show up on iPhones or flagship devices.

Isolate animated components

Wrap animated elements in their own container so React doesn’t re-render unrelated UI.

Use consistent timing

A cohesive animation system feels intentional rather than “random”.

These rules dramatically improve smoothness with minimal effort.


What to Explore Next

Once these foundational text and micro-interaction patterns feel familiar, the natural next step is motion driven by touch. Gesture-based animations form the backbone of many modern app experiences: swiping cards, pulling panels, sorting lists, revealing drawers, or dismissing notifications. They’re expressive, intuitive, and a big part of how mobile interfaces feel alive.

Exploring gestures opens the door to richer interactions such as:

  • drag-driven transitions
  • swipe-to-dismiss patterns
  • Tinder-style stacked cards
  • pull-to-reveal surfaces
  • scroll-linked effects

These patterns build on the same principles used in this guide; they simply add user input into the mix. Studying them provides a deeper understanding of how motion supports usability and emotion in mobile products.

Closing Thoughts

Motion isn’t a layer applied at the end of a design.
It’s part of how an app speaks.

Even small, subtle animations contribute to the feeling that an interface is thoughtful and alive. Mastering these foundations makes it easier to design onboarding flows, product moments, and micro-experiences that feel coherent and intentional.

Top comments (0)