DEV Community

Fazal Shah
Fazal Shah

Posted on

How to Use Lottie Animations in React Native (2025 Guide)

Lottie animations work natively in React Native — no WebView, no GIFs, no video embeds. This guide covers everything from setup to performance, including the critical differences from the web implementation.


Why Lottie in React Native?

  • Native rendering: Lottie animations render via native Android/iOS drawing APIs, not a web view. Smooth on both platforms.
  • Tiny files: A 3-second animation is typically 10–40KB — vs 300KB+ for a comparable GIF
  • Scriptable: Play, pause, loop, seek, change speed, and even react to gestures
  • Shared source files: The same .json or .lottie file works on iOS, Android, and the web

Step 0: Preview Before You Build

Before adding any Lottie file to React Native, open it in IconKing:

  • See exact colors, timing, and layer structure
  • Edit colors to match your app's design system (saves re-exporting from After Effects)
  • Convert .json.lottie for smaller bundle size
  • Catch unsupported After Effects effects before they silently fail on device

No account required, runs entirely in the browser.


Installation

The lottie-react-native library is the standard React Native Lottie renderer:

npm install lottie-react-native
Enter fullscreen mode Exit fullscreen mode

For iOS, install pods:

cd ios && pod install
Enter fullscreen mode Exit fullscreen mode

Minimum version requirements:

  • iOS 11+
  • Android API 21+ (Android 5.0)
  • React Native 0.71+

Basic Usage

import LottieView from 'lottie-react-native';

export default function LoadingScreen() {
  return (
    <LottieView
      source={require('./animations/loading.json')}
      autoPlay
      loop
      style={{ width: 200, height: 200 }}
    />
  );
}
Enter fullscreen mode Exit fullscreen mode

The source prop accepts either:

  • require('./file.json') — bundled with the app
  • { uri: 'https://...' } — fetched at runtime

Programmatic Control with ref

import { useRef } from 'react';
import LottieView from 'lottie-react-native';

export default function AnimatedButton({ onPress }) {
  const animRef = useRef(null);

  return (
    <Pressable
      onPress={() => {
        animRef.current?.play();
        onPress?.();
      }}
    >
      <LottieView
        ref={animRef}
        source={require('./animations/tap.json')}
        autoPlay={false}
        loop={false}
        style={{ width: 48, height: 48 }}
      />
    </Pressable>
  );
}
Enter fullscreen mode Exit fullscreen mode

Available ref methods:

  • animRef.current.play() — play from current position
  • animRef.current.play(startFrame, endFrame) — play a specific segment
  • animRef.current.reset() — reset to frame 0
  • animRef.current.pause() — pause at current frame
  • animRef.current.resume() — resume from paused position

Loop and Autoplay

{/* Loop forever, start immediately */}
<LottieView source={require('./loading.json')} autoPlay loop />

{/* Play once on mount */}
<LottieView source={require('./success.json')} autoPlay loop={false} />

{/* Manual control only */}
<LottieView ref={animRef} source={require('./hover.json')} autoPlay={false} loop={false} />
Enter fullscreen mode Exit fullscreen mode

Listening for Completion

import { useState } from 'react';

export default function SuccessAnimation({ onDone }) {
  return (
    <LottieView
      source={require('./animations/success.json')}
      autoPlay
      loop={false}
      onAnimationFinish={(isCancelled) => {
        if (!isCancelled) onDone?.();
      }}
      style={{ width: 120, height: 120 }}
    />
  );
}
Enter fullscreen mode Exit fullscreen mode

Loading State Pattern

import { useState } from 'react';
import { View, Pressable, Text } from 'react-native';
import LottieView from 'lottie-react-native';

type Status = 'idle' | 'loading' | 'success';

export default function SubmitButton({ onSubmit }) {
  const [status, setStatus] = useState<Status>('idle');

  async function handlePress() {
    setStatus('loading');
    try {
      await onSubmit();
      setStatus('success');
    } catch {
      setStatus('idle');
    }
  }

  return (
    <Pressable
      onPress={handlePress}
      disabled={status !== 'idle'}
      style={styles.button}
    >
      {status === 'idle' && <Text style={styles.label}>Submit</Text>}

      {status === 'loading' && (
        <LottieView
          source={require('./animations/loading.json')}
          autoPlay
          loop
          style={{ width: 32, height: 32 }}
        />
      )}

      {status === 'success' && (
        <LottieView
          source={require('./animations/success.json')}
          autoPlay
          loop={false}
          onAnimationFinish={() => setStatus('idle')}
          style={{ width: 32, height: 32 }}
        />
      )}
    </Pressable>
  );
}
Enter fullscreen mode Exit fullscreen mode

Speed and Direction

{/* Half speed */}
<LottieView source={require('./anim.json')} autoPlay speed={0.5} />

{/* Double speed */}
<LottieView source={require('./anim.json')} autoPlay speed={2} />
Enter fullscreen mode Exit fullscreen mode

Changing Colors at Runtime

Use colorFilters to retheme animations without touching the source file:

<LottieView
  source={require('./icon.json')}
  autoPlay
  loop
  colorFilters={[
    {
      keypath: 'Icon Fill',    // layer name in After Effects
      color: '#FF6B6B',         // new color (hex)
    },
    {
      keypath: 'Background',
      color: '#1A1A2E',
    }
  ]}
/>
Enter fullscreen mode Exit fullscreen mode

To find the correct layer names, open the file in IconKing and inspect the layer panel — the names map directly to keypath values.


Using dotLottie (.lottie) Format

lottie-react-native v6.0+ supports .lottie files natively:

<LottieView
  source={require('./animations/loading.lottie')}
  autoPlay
  loop
/>
Enter fullscreen mode Exit fullscreen mode

.lottie files are ~75% smaller than .json. Convert at IconKing.

For older versions, use the JSON format.


Expo Setup

In Expo managed workflow, lottie-react-native requires the expo-av or expo plugin:

// app.json
{
  "expo": {
    "plugins": ["lottie-react-native"]
  }
}
Enter fullscreen mode Exit fullscreen mode

Then rebuild:

npx expo run:ios
# or
npx expo run:android
Enter fullscreen mode Exit fullscreen mode

Note: Lottie does not work in Expo Go (the sandbox app). You need a development build.


Performance Tips

1. Use .lottie format

Convert at IconKing — 75% smaller = faster app startup, less memory.

2. Avoid large animations on list items

Rendering a Lottie animation in every cell of a FlatList is expensive. Use simpler static icons for list rows, and reserve animations for standalone screens.

3. Pause when not visible

import { useIsFocused } from '@react-navigation/native';

export default function AnimatedScreen() {
  const isFocused = useIsFocused();

  return (
    <LottieView
      source={require('./bg-animation.json')}
      autoPlay={isFocused}
      loop
    />
  );
}
Enter fullscreen mode Exit fullscreen mode

4. Resize correctly

Don't use flex: 1 on a LottieView inside a scroll container — it causes layout thrashing. Always provide explicit width and height.


Common Issues

Animation not showing on iOS

  1. Run pod install in the /ios directory
  2. Clean build folder (Xcode → Product → Clean Build Folder)
  3. Rebuild

Colors look wrong on Android

Android and iOS render some After Effects effects differently. Open the file in IconKing to see the browser render. If browser and device differ, the issue is in the export. Ask your designer to avoid blend modes and use flat fills.

onAnimationFinish fires immediately

The animation has 0 frames or an error. Check the file is valid by opening it in IconKing.

White flash before animation starts

Set resizeMode="cover" and add a background color matching your animation's first frame.


Where to Get Lottie Files

  • LottieFiles — largest free Lottie library; search by keyword
  • Your designer — have them export from After Effects using Bodymovin
  • IconKing — preview any file before using, edit colors, convert formats

Summary

  1. npm install lottie-react-native + pod install for iOS
  2. Use <LottieView source={require(...)} autoPlay loop /> for basic use
  3. ref gives you .play(), .pause(), .reset(), .resume()
  4. onAnimationFinish fires when a non-looping animation completes
  5. colorFilters changes colors without touching the source file
  6. Pause with useIsFocused() when the screen is off-screen
  7. Convert to .lottie at IconKing for smaller bundle size

Top comments (0)