Using Lottie Animations in React

Loading

Lottie is a powerful library for rendering Adobe After Effects animations natively in web and mobile applications. Here’s how to effectively integrate Lottie animations in your React projects.

1. Basic Lottie Integration

Installation

npm install lottie-react
# or
yarn add lottie-react

Basic Implementation

import Lottie from 'lottie-react';
import animationData from './animation.json';

function BasicAnimation() {
  return <Lottie animationData={animationData} />;
}

2. Animation Control

Playback Control

import { useRef } from 'react';
import Lottie from 'lottie-react';

function ControlledAnimation() {
  const lottieRef = useRef();

  const playAnimation = () => {
    lottieRef.current.play();
  };

  const pauseAnimation = () => {
    lottieRef.current.pause();
  };

  const stopAnimation = () => {
    lottieRef.current.stop();
  };

  return (
    <div>
      <Lottie
        lottieRef={lottieRef}
        animationData={animationData}
        loop={false}
      />
      <div className="controls">
        <button onClick={playAnimation}>Play</button>
        <button onClick={pauseAnimation}>Pause</button>
        <button onClick={stopAnimation}>Stop</button>
      </div>
    </div>
  );
}

Segment Playback

function SegmentAnimation() {
  return (
    <Lottie
      animationData={animationData}
      segments={[10, 50]} // Play frames 10-50
      initialSegment={[0, 10]} // Initial segment (optional)
    />
  );
}

3. Advanced Configuration

Event Handlers

function EventAnimation() {
  const handleComplete = () => {
    console.log('Animation completed!');
  };

  const handleLoopComplete = () => {
    console.log('Loop completed!');
  };

  return (
    <Lottie
      animationData={animationData}
      onComplete={handleComplete}
      onLoopComplete={handleLoopComplete}
      loop={true}
    />
  );
}

Dynamic Loading

import { useState, useEffect } from 'react';

function DynamicAnimation({ animationPath }) {
  const [animationData, setAnimationData] = useState(null);

  useEffect(() => {
    fetch(animationPath)
      .then(response => response.json())
      .then(data => setAnimationData(data));
  }, [animationPath]);

  if (!animationData) return <div>Loading animation...</div>;

  return <Lottie animationData={animationData} />;
}

4. Performance Optimization

Lightweight Wrapper

import { useRef, useEffect } from 'react';
import lottie from 'lottie-web';

function LightweightLottie({ animationData }) {
  const containerRef = useRef();
  const animationRef = useRef();

  useEffect(() => {
    animationRef.current = lottie.loadAnimation({
      container: containerRef.current,
      renderer: 'svg',
      loop: true,
      autoplay: true,
      animationData: animationData,
    });

    return () => {
      animationRef.current?.destroy();
    };
  }, [animationData]);

  return <div ref={containerRef} style={{ width: 300, height: 300 }} />;
}

Intersection Observer (Lazy Loading)

import { useRef, useEffect, useState } from 'react';

function LazyLottie({ animationData }) {
  const containerRef = useRef();
  const [isVisible, setIsVisible] = useState(false);

  useEffect(() => {
    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setIsVisible(true);
          observer.unobserve(entry.target);
        }
      },
      { threshold: 0.1 }
    );

    if (containerRef.current) {
      observer.observe(containerRef.current);
    }

    return () => {
      if (containerRef.current) {
        observer.unobserve(containerRef.current);
      }
    };
  }, []);

  useEffect(() => {
    if (!isVisible) return;

    const anim = lottie.loadAnimation({
      container: containerRef.current,
      renderer: 'svg',
      loop: true,
      autoplay: true,
      animationData: animationData,
    });

    return () => anim.destroy();
  }, [isVisible, animationData]);

  return <div ref={containerRef} style={{ width: '100%', height: '100%' }} />;
}

5. Interactive Animations

Scroll-Triggered Animation

import { useRef, useEffect } from 'react';
import lottie from 'lottie-web';

function ScrollAnimation({ animationData }) {
  const containerRef = useRef();
  const animRef = useRef();
  const scrollRef = useRef(0);

  useEffect(() => {
    animRef.current = lottie.loadAnimation({
      container: containerRef.current,
      renderer: 'svg',
      animationData: animationData,
      autoplay: false,
    });

    const handleScroll = () => {
      const scrollPosition = window.scrollY;
      const maxScroll = document.body.scrollHeight - window.innerHeight;
      const scrollProgress = scrollPosition / maxScroll;

      const totalFrames = animRef.current.totalFrames;
      const targetFrame = Math.floor(scrollProgress * totalFrames);

      animRef.current.goToAndStop(targetFrame, true);
    };

    window.addEventListener('scroll', handleScroll);
    return () => {
      animRef.current?.destroy();
      window.removeEventListener('scroll', handleScroll);
    };
  }, [animationData]);

  return <div ref={containerRef} style={{ height: '200vh' }} />;
}

Click-Triggered Animation

function ClickAnimation() {
  const lottieRef = useRef();

  const handleClick = () => {
    lottieRef.current.playSegments([0, 30], true);
  };

  return (
    <div onClick={handleClick} style={{ cursor: 'pointer' }}>
      <Lottie
        lottieRef={lottieRef}
        animationData={animationData}
        autoplay={false}
        loop={false}
      />
    </div>
  );
}

6. Custom Styling and Theming

Dynamic Color Changes

import { useEffect, useRef } from 'react';

function ThemedAnimation({ primaryColor = '#ff0000' }) {
  const animationRef = useRef();

  useEffect(() => {
    if (animationRef.current) {
      animationRef.current.setColors({
        keypath: 'Layer1.Shape1.Fill', // Path to color property in animation
        color: primaryColor,
      });
    }
  }, [primaryColor]);

  return (
    <Lottie
      lottieRef={animationRef}
      animationData={animationData}
    />
  );
}

Responsive Sizing

function ResponsiveAnimation() {
  return (
    <div style={{ width: '100%', height: '100%', maxWidth: 600 }}>
      <Lottie
        animationData={animationData}
        style={{ width: '100%', height: '100%' }}
      />
    </div>
  );
}

7. Advanced Patterns

Animation Chaining

function AnimationSequence() {
  const firstAnimRef = useRef();
  const secondAnimRef = useRef();

  const playSequence = () => {
    firstAnimRef.current.play();
    firstAnimRef.current.addEventListener('complete', () => {
      secondAnimRef.current.play();
    });
  };

  return (
    <div>
      <Lottie
        lottieRef={firstAnimRef}
        animationData={firstAnimation}
        loop={false}
        autoplay={false}
      />
      <Lottie
        lottieRef={secondAnimRef}
        animationData={secondAnimation}
        loop={false}
        autoplay={false}
      />
      <button onClick={playSequence}>Play Sequence</button>
    </div>
  );
}

State-Driven Animations

function StatefulAnimation({ isActive }) {
  const lottieRef = useRef();

  useEffect(() => {
    if (isActive) {
      lottieRef.current.playSegments([0, 30], true);
    } else {
      lottieRef.current.playSegments([30, 60], true);
    }
  }, [isActive]);

  return (
    <Lottie
      lottieRef={lottieRef}
      animationData={animationData}
      autoplay={false}
    />
  );
}

Best Practices for Lottie in React

  1. Optimize JSON Files: Use tools like LottieFiles Optimizer to reduce file size
  2. Lazy Load: Only load animations when needed (especially for below-the-fold content)
  3. Reuse Instances: Cache animation data when using the same animation multiple times
  4. Fallbacks: Provide static image fallbacks for slow connections
  5. Performance Monitoring: Test animations on low-end devices
  6. Accessibility: Add ARIA labels and keyboard controls for interactive animations
  7. Cleanup: Always destroy animations on component unmount to prevent memory leaks

Troubleshooting Common Issues

Problem: Animation not playing

  • Solution: Check if animationData is properly loaded
  • Solution: Verify autoplay is enabled or manually trigger play()

Problem: Animation looks distorted

  • Solution: Ensure container dimensions match animation’s aspect ratio
  • Solution: Check for conflicting CSS transforms

Problem: Poor performance

  • Solution: Reduce animation complexity in After Effects
  • Solution: Use canvas renderer instead of SVG for complex animations

Problem: Colors not changing

  • Solution: Verify color keypaths match the animation structure
  • Solution: Check if animation has restricted color editing enabled

By implementing these Lottie animation techniques in your React applications, you can create rich, engaging user experiences with smooth, vector-based animations that work across all modern browsers and devices.

Leave a Reply

Your email address will not be published. Required fields are marked *