Motionary6 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