Implementing Lottie Animations on a Website
Lottie is a JSON format for vector animations exported from Adobe After Effects via the Bodymovin plugin. Animations are played through JavaScript or native renderers, maintaining quality at any DPI. Primary uses include icons, illustrations, loaders, and empty states.
Installation
# Lightweight player — SVG renderer only, ~60 KB gzip
npm install @lottiefiles/dotlottie-react
# Alternative — lottie-react (full renderer, ~180 KB gzip)
npm install lottie-react
DotLottie is a newer format (.lottie, binary zip) recommended for new projects: 10 times lighter than JSON equivalent.
Basic Component
// components/LottieAnimation.tsx
import { DotLottieReact } from '@lottiefiles/dotlottie-react'
interface LottieAnimationProps {
src: string // URL or path to .lottie/.json
loop?: boolean
autoplay?: boolean
className?: string
onComplete?: () => void
}
export function LottieAnimation({
src,
loop = true,
autoplay = true,
className,
onComplete,
}: LottieAnimationProps) {
return (
<DotLottieReact
src={src}
loop={loop}
autoplay={autoplay}
className={className}
onComplete={onComplete}
/>
)
}
Playback Control
// components/ControlledLottie.tsx
import { useRef, useState } from 'react'
import { DotLottieReact, DotLottie } from '@lottiefiles/dotlottie-react'
export function ControlledLottie({ src }: { src: string }) {
const [dotLottie, setDotLottie] = useState<DotLottie | null>(null)
const play = () => dotLottie?.play()
const pause = () => dotLottie?.pause()
const stop = () => dotLottie?.stop()
const setSpeed = (speed: number) => dotLottie?.setSpeed(speed)
const seekTo = (frame: number) => dotLottie?.setFrame(frame)
return (
<div>
<DotLottieReact
src={src}
loop={false}
autoplay={false}
dotLottieRefCallback={setDotLottie}
/>
<div className="flex gap-2 mt-4">
<button onClick={play}>Play</button>
<button onClick={pause}>Pause</button>
<button onClick={stop}>Stop</button>
<button onClick={() => setSpeed(2)}>2x</button>
</div>
</div>
)
}
Hover Animation (Interactive Icon)
// components/AnimatedIcon.tsx
import { useRef, useState } from 'react'
import { DotLottieReact, DotLottie } from '@lottiefiles/dotlottie-react'
interface AnimatedIconProps {
src: string
size?: number
hoverToPlay?: boolean
}
export function AnimatedIcon({ src, size = 32, hoverToPlay = true }: AnimatedIconProps) {
const [dotLottie, setDotLottie] = useState<DotLottie | null>(null)
const handleMouseEnter = () => {
if (hoverToPlay && dotLottie) {
dotLottie.stop()
dotLottie.play()
}
}
return (
<div
onMouseEnter={handleMouseEnter}
style={{ width: size, height: size }}
className="cursor-pointer"
>
<DotLottieReact
src={src}
loop={false}
autoplay={false}
dotLottieRefCallback={setDotLottie}
/>
</div>
)
}
Lottie Loader
// components/LottieLoader.tsx
import { DotLottieReact } from '@lottiefiles/dotlottie-react'
export function PageLoader() {
return (
<div className="fixed inset-0 flex items-center justify-center bg-white z-50">
<DotLottieReact
src="/animations/loader.lottie"
loop
autoplay
style={{ width: 120, height: 120 }}
/>
</div>
)
}
// Usage with Suspense/data loading
export function DataLoader({ isLoading }: { isLoading: boolean }) {
if (!isLoading) return null
return (
<div className="flex justify-center py-12">
<DotLottieReact
src="/animations/spinner.lottie"
loop
autoplay
style={{ width: 64, height: 64 }}
/>
</div>
)
}
Load Optimization
Lottie files can be preloaded and cached:
// lib/lottie-cache.ts
const cache = new Map<string, object>()
export async function preloadLottie(src: string): Promise<void> {
if (cache.has(src)) return
const res = await fetch(src)
const data = await res.json()
cache.set(src, data)
}
export function getCachedLottie(src: string): object | undefined {
return cache.get(src)
}
For JSON format via lottie-react, you can import the animation directly — the bundler will include it in the chunk:
import Lottie from 'lottie-react'
import successAnimation from '@/animations/success.json'
export function SuccessAnimation() {
return (
<Lottie
animationData={successAnimation}
loop={false}
style={{ width: 200, height: 200 }}
/>
)
}
For .lottie format, use CDN or /public folder — don't import directly, binary files aren't processed by standard bundler loaders without configuration.
Typical Timelines
Integration of ready-made animations from LottieFiles.com — 2–4 hours. Full setup with caching, playback control, and responsive sizing — 1 working day.







