How to Use Animated View in React Native

Animated.View is the built-in React Native way to animate a view's opacity,
transform, position, and other supported styles. It is still useful for simple
microinteractions: fade-ins, scale feedback, loading motion, card entrance
animations, and small transitions that do not need complex gesture logic.
For heavy gesture-driven UI, shared element transitions, and UI-thread worklets,
React Native Reanimated is usually the better tool. For simple screen polish,
the core Animated API is still enough.
Quick Answer
Create an Animated.Value, store it in a ref, drive it with
Animated.timing, Animated.spring, Animated.sequence, or
Animated.parallel, and set useNativeDriver: true when animating supported
properties such as opacity and transform.
import { useEffect, useRef } from 'react';
import { Animated, Text } from 'react-native';
export function FadeInCard() {
const opacity = useRef(new Animated.Value(0)).current;
useEffect(() => {
Animated.timing(opacity, {
toValue: 1,
duration: 240,
useNativeDriver: true,
}).start();
}, [opacity]);
return (
<Animated.View style={{ opacity }}>
<Text>Ready</Text>
</Animated.View>
);
}
If your animation depends on gestures, scroll position, or continuous UI-thread updates, check the current React Native stack and consider Reanimated.
Use a Ref for Animated Values
Do not recreate animated values on every render. Store them in useRef:
const scale = useRef(new Animated.Value(0.96)).current;
Then run animations from effects or event handlers:
function pressIn() {
Animated.spring(scale, {
toValue: 0.98,
useNativeDriver: true,
}).start();
}
function pressOut() {
Animated.spring(scale, {
toValue: 1,
useNativeDriver: true,
}).start();
}
Fade In a View
Opacity is a good fit for the native driver:
import { PropsWithChildren, useEffect, useRef } from 'react';
import { Animated, StyleProp, ViewStyle } from 'react-native';
export function FadeInView({
children,
style,
}: PropsWithChildren<{ style?: StyleProp<ViewStyle> }>) {
const opacity = useRef(new Animated.Value(0)).current;
useEffect(() => {
Animated.timing(opacity, {
toValue: 1,
duration: 220,
useNativeDriver: true,
}).start();
}, [opacity]);
return <Animated.View style={[style, { opacity }]}>{children}</Animated.View>;
}
Use short durations for UI feedback. Long animations can make the app feel slow.
Mega Bundle Sale is ON! Get ALL of our React Native codebases at 90% OFF discount 🔥
Get the Mega BundleScale a Pressable Card
transform properties also work with the native driver:
import { PropsWithChildren, useRef } from 'react';
import { Animated, Pressable } from 'react-native';
export function PressableScale({ children }: PropsWithChildren) {
const scale = useRef(new Animated.Value(1)).current;
function animate(toValue: number) {
Animated.spring(scale, {
toValue,
speed: 18,
bounciness: 4,
useNativeDriver: true,
}).start();
}
return (
<Pressable onPressIn={() => animate(0.97)} onPressOut={() => animate(1)}>
<Animated.View style={{ transform: [{ scale }] }}>
{children}
</Animated.View>
</Pressable>
);
}
This pattern works well for cards, icon buttons, product tiles, and list items.
Rotate With Interpolation
Use interpolation when the animated value needs to map to a string or derived range:
import { useEffect, useRef } from 'react';
import { Animated, Easing } from 'react-native';
export function LoadingSpinner() {
const progress = useRef(new Animated.Value(0)).current;
useEffect(() => {
const animation = Animated.loop(
Animated.timing(progress, {
toValue: 1,
duration: 900,
easing: Easing.linear,
useNativeDriver: true,
})
);
animation.start();
return () => animation.stop();
}, [progress]);
const rotate = progress.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg'],
});
return <Animated.View style={{ transform: [{ rotate }] }} />;
}
Always stop loops when the component unmounts.
Run Animations in Sequence or Parallel
Use Animated.sequence when one step should start after another:
Animated.sequence([
Animated.timing(opacity, {
toValue: 1,
duration: 180,
useNativeDriver: true,
}),
Animated.spring(scale, {
toValue: 1,
useNativeDriver: true,
}),
]).start();
Use Animated.parallel when multiple values should move together:
Animated.parallel([
Animated.timing(opacity, {
toValue: 1,
duration: 180,
useNativeDriver: true,
}),
Animated.spring(translateY, {
toValue: 0,
useNativeDriver: true,
}),
]).start();
Native Driver Rules
Use the native driver whenever possible. It sends supported animation work to native before the animation starts, so the animation can continue even if the JavaScript thread is busy.
The native driver works well with:
opacity;transformvalues such as scale, translate, and rotate;- event-driven animations supported by
Animated.event.
It does not support every style property. Layout properties such as height,
width, and some color/layout changes may need another approach. If your design
needs layout transitions, evaluate Reanimated or LayoutAnimation.
Looking for a custom mobile application?
Our team of expert mobile developers can help you build a custom mobile app that meets your specific needs.
Get in TouchFAQ
Should I use Animated or Reanimated?
Use Animated for small one-off interactions. Use Reanimated for complex
gestures, bottom sheets, carousels, shared values, and UI-thread animations.
Why does React Native require useNativeDriver?
React Native requires you to choose whether an animation should run on the native
driver. Use true for supported properties like opacity and transforms.
Can I animate height with the native driver?
Usually no. Height is a layout property. Prefer transform-based motion or a layout animation library for that kind of transition.