Skip to content
All posts

6 min read

React Native animation: which library to use in 2026

Reanimated, Animated, Moti, Ease, Skia, Lottie or Rive? What each React Native animation library is for, with code and an honest pick for each job.

For React Native animation in 2026, use Reanimated unless you have a specific reason not to. It runs on the UI thread, handles gestures and layout changes, and everything else on this list is either narrower or built on top of it. Add react-native-ease for simple state-driven transitions, Skia when you need to draw pixels, and Lottie or Rive when a designer is making the art.

We have built more than 60 animated components at Motionary, nearly all on Reanimated with the showier ones on Skia, so this is the shortlist we would hand a friend. Versions and maintenance dates were checked on npm in November 2026.

Which React Native animation library should you use?

You want Use Runs where Expo Go
The default for anything interactive react-native-reanimated UI thread Yes
One fade with no new dependency Animated, built in JS, or native with useNativeDriver Yes
A list item reflowing, once LayoutAnimation, built in Native Yes
Simple transitions on state changes react-native-ease Core Animation and Animator Needs a dev build
Shaders, charts, blurs, custom drawing @shopify/react-native-skia GPU canvas Yes
Art exported from After Effects lottie-react-native Native player Yes
Designer-built interactive state machines @rive-app/react-native Native renderer Needs a dev build

Why does the thread matter so much?

Your JavaScript runs on one thread and your screen is drawn on another. An animation driven from JavaScript has to get a value across on every frame, so when JS is busy parsing a response or rendering a list, the animation stutters. Every serious option here exists to take JavaScript out of that per-frame path. How they do it is the real difference between them. (The JS thread also stops entirely once the app is backgrounded, which is a different problem with a different fix.)

Is the built-in Animated API still worth using?

For small things, yes. Animated ships with React Native, so a fade costs you no dependency. Set useNativeDriver: true and the animation runs off the JS thread. The catch is that the native driver only supports properties that don't affect layout, such as opacity and transform. Animate height or width and you are back on the JS thread.

import { useRef } from 'react';
import { Animated, Pressable, Text } from 'react-native';

export function PressScale({ title }: { title: string }) {
  const scale = useRef(new Animated.Value(1)).current;

  const to = (value: number) =>
    Animated.spring(scale, { toValue: value, useNativeDriver: true }).start();

  return (
    <Pressable onPressIn={() => to(0.96)} onPressOut={() => to(1)}>
      <Animated.View style={{ transform: [{ scale }] }}>
        <Text>{title}</Text>
      </Animated.View>
    </Pressable>
  );
}

LayoutAnimation is the other built-in, and it is good at exactly one thing: "the next layout change should animate". Call it before a state update and rows slide into place instead of snapping. On the New Architecture it is enabled automatically. You get very little control, so reach for it when you want the effect and don't care about the details.

Why is Reanimated the default?

Because it is the one that doesn't run out of road. Your animation logic runs as a worklet on the UI thread, so it keeps moving when JavaScript is busy, and it can read a finger position directly during a gesture. That second part is what Animated can't do well, and it is most of what makes an app feel native.

import { Pressable, Text } from 'react-native';
import Animated, {
  useAnimatedStyle,
  useSharedValue,
  withSpring,
} from 'react-native-reanimated';

export function PressScale({ title }: { title: string }) {
  const scale = useSharedValue(1);

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

  return (
    <Pressable
      onPressIn={() => (scale.value = withSpring(0.96))}
      onPressOut={() => (scale.value = withSpring(1))}
    >
      <Animated.View style={style}>
        <Text>{title}</Text>
      </Animated.View>
    </Pressable>
  );
}

Reanimated 4 also added CSS-style transitions, which cover a lot of everyday work in a couple of lines and don't need a shared value at all:

import Animated from 'react-native-reanimated';

export function Bar({ open }: { open: boolean }) {
  return (
    <Animated.View
      style={{
        height: 8,
        width: open ? 240 : 80,
        backgroundColor: '#111111',
        transitionProperty: 'width',
        transitionDuration: 220,
      }}
    />
  );
}

For items entering, leaving or reflowing, the entering, exiting and layout props do the work. Two costs to know about: version 4 requires the New Architecture, and it pulls in react-native-worklets as a separate package. It is bundled in Expo Go, so you can start without a development build. You can see what it looks like pushed hard in our hold-to-confirm button.

What is react-native-ease, and when does it beat Reanimated?

react-native-ease is the newest name on this list and the most interesting idea. It hands the animation to the platform, Core Animation on iOS and Animator on Android, so no JavaScript or worklet runs per frame at all. You declare a target and a transition:

import { EaseView } from 'react-native-ease';

export function Card({ visible }: { visible: boolean }) {
  return (
    <EaseView
      animate={{ opacity: visible ? 1 : 0 }}
      transition={{ type: 'timing', duration: 300 }}
      style={{ height: 120, borderRadius: 16, backgroundColor: '#111111' }}
    />
  );
}

Its own README is clear about the limits, which is a good sign. It is not for gesture-driven animation, worklets, shared values across components or shared element transitions, and it is Fabric only (React Native 0.76+). So it is a specialist: fades and slides on state changes, especially when a lot of them run at once. It needs a development build, and it sits happily next to Reanimated rather than replacing it.

Is Moti still worth using?

Moti is a friendly declarative layer on top of Reanimated, and for a long time it was the nicest way to write simple animations. It still works. But the last npm release, 0.30.0, is from January 2025, and Reanimated's CSS transitions now cover much of what people used it for. On a new project we would write those animations directly in Reanimated. If you have a codebase full of working Moti, there is no reason to rip it out.

The same goes more firmly for react-native-animatable, whose last publish was October 2023. Don't start anything new on it.

When do you need Skia?

When the thing you are animating isn't really a view. Shaders, path morphing, charts, particles and custom blurs all need a GPU canvas, and that is @shopify/react-native-skia. It pairs directly with Reanimated, so a shared value can drive a shader uniform with no bridge in the middle. Our pool water shader and the electric border are both this kind of work.

It does add meaningful size to your app, and you get a drawing API rather than components. If what you want is a blurred panel over real content, you probably want a native BlurView instead, because Skia can only blur what it drew itself.

Lottie or Rive?

Both are for art someone else made, and neither is a replacement for coding your UI motion. lottie-react-native plays animations exported from After Effects. It is the safe pick when a designer already works there and you want an icon or an illustration to play from start to finish.

Rive is built for interaction: the designer builds a state machine, and your code flips inputs on it. Choose it when the art has to respond to the app. Watch the package name, because the current runtime is @rive-app/react-native, built on Nitro, and older tutorials point at rive-react-native.

Which one for which job?

  • Button press, toggle, sheet, drag: Reanimated.
  • Loading states: Reanimated, with the layout mirrored, as in our guides to skeleton loading and AI loading animations.
  • A hundred cards fading in on a state change: try Ease.
  • A single fade, and you want zero dependencies: Animated.
  • Charts, shaders, particles: Skia, driven by Reanimated.
  • An illustration from your designer: Lottie, or Rive if it has to react.

If you are also picking the components those animations live in, we keep an honest map of React Native UI libraries, and free references for everyday controls like the text field. And if you would rather skip writing the animation entirely, the drops are finished Reanimated and Skia components, source code included.

What is the best animation library for React Native?

Reanimated is the best default in 2026. It runs animations on the UI thread, drives gestures directly and handles layout transitions, and it works in Expo Go. Use Skia alongside it for custom drawing, and Lottie or Rive for art made by a designer.

What is the difference between Animated and Reanimated?

Animated is built into React Native and can only run off the JavaScript thread for non-layout properties like opacity and transform, using useNativeDriver. Reanimated is a library that runs your animation code on the UI thread for any style, and can respond to a finger during a gesture without going through JavaScript.

Does Reanimated work in Expo Go?

Yes. Reanimated is bundled in Expo Go, so you can install it with npx expo install react-native-reanimated react-native-worklets and use it without a development build. Version 4 requires the New Architecture, which is what current Expo SDKs use.

Is Moti still maintained?

Moti still works, but its last npm release was 0.30.0 in January 2025. It is a wrapper around Reanimated, so existing code keeps running. For new work, Reanimated's own CSS transitions and layout animations cover most of the same ground with one less dependency.

Do I need a library to animate in React Native?

Not for simple cases. The built-in Animated API handles fades and transforms, and LayoutAnimation handles one-off layout changes. You will want Reanimated as soon as an animation has to follow a gesture, stay smooth while JavaScript is busy, or animate layout properties like width.

React NativeExpoReanimatedSkiaAnimation