@jurneyx2/react-lottie-hooks
v1.2.7
Published
π― Simple and powerful React hooks for DotLottie animations with GSAP ScrollTrigger integration and automatic SSR/CSR detection
Maintainers
Readme
π― React Lottie Hooks v1.2.7 (DotLottie)
Simple and powerful React hooks for DotLottie animations with GSAP ScrollTrigger
β¨ Easily implement scroll-based animations with React hooks optimized exclusively for DotLottie!
v1.2.7 is the latest stable release - Enhanced with full internationalization, ES Module compatibility, and security improvements
π View Live Examples | π¦ NPM Package | π Documentation
π Features
- π¨ DotLottie Exclusive: Perfect support for
@lottiefiles/dotlottie-react - π± SSR/CSR Safe: Full compatibility with SSR frameworks like Next.js, Remix, React Router
- π― GSAP ScrollTrigger: Scroll-based animations and effects
- π§ TypeScript: Complete type safety
- πͺ Simple API: Ready to use without complex configuration
- β‘ Optimized: Performance and memory efficiency optimized
- π¨ 4 Complete Examples: Next.js, Vite, Remix, and React Router implementations with full source code
- π Internationalization: Debug messages in Korean and English
- π¦ ES Module Compatible: Works with all modern bundlers (Vite, Webpack, esbuild)
π What's New in v1.2.7
π Security & Performance Improvements
Enhanced library security and bundle optimization:
// No source maps in production builds for better security
// Reduced bundle size and protected source codeπ¦ Enhanced ES Module Compatibility
Improved GSAP ScrollTrigger integration for React Router v7:
// Automatic handling of .js extensions in ESM environments
// Perfect compatibility with React Router v7 framework mode
const hook = useLottieScrollTrigger({
start: "top center",
end: "bottom center",
});π οΈ Build Optimizations
- Security: Removed source maps from production builds
- Bundle Size: Optimized output size for better performance
- ESM Support: Enhanced compatibility with strict ESM environments
π¦ Installation
# npm (recommended)
npm install @jurneyx2/react-lottie-hooks @lottiefiles/dotlottie-react gsap
# pnpm
pnpm add @jurneyx2/react-lottie-hooks @lottiefiles/dotlottie-react gsap
# yarn
yarn add @jurneyx2/react-lottie-hooks @lottiefiles/dotlottie-react gsapπ― Basic Usage
import React from "react";
import { DotLottieReact } from "@lottiefiles/dotlottie-react";
import { useLottieScrollTrigger } from "@jurneyx2/react-lottie-hooks";
export default function ScrollAnimation() {
const { triggerRef, handleDotLottieRef, isLoaded } = useLottieScrollTrigger({
start: "top center",
end: "bottom 20%",
debug: process.env.NODE_ENV === "development",
});
return (
<div>
{/* Scroll trigger area */}
<div ref={triggerRef} style={{ height: "100vh" }}>
<h2>Animation starts when you scroll!</h2>
{/* DotLottie animation */}
<DotLottieReact
src="/animations/my-animation.lottie"
loop={false}
autoplay={false}
dotLottieRefCallback={handleDotLottieRef}
className="w-full h-full"
/>
</div>
{isLoaded && <p>Animation has been loaded! β¨</p>}
</div>
);
}π¨ Advanced Usage
Using with GSAP Animations
const {
triggerRef,
handleDotLottieRef,
play,
pause,
currentFrame,
} = useLottieScrollTrigger({
start: "top bottom",
end: "bottom top",
// GSAP animation effects
gsapAnimations: {
scale: 1.2,
rotation: 360,
opacity: 0.8,
duration: 2,
ease: "power2.out",
trigger: "enter",
scrub: true, // Sync with scroll
},
// Custom event handlers
onEnter: (dotLottie) => {
console.log("Entered animation area!");
dotLottie.setSpeed(1.5);
},
```
### Performance Optimized Usage
```tsx
function PerformanceOptimizedLottie() {
const {
triggerRef,
handleDotLottieRef,
getCurrentFrame, // ref-based getter (no re-renders)
getIsPlaying, // ref-based getter (no re-renders)
play,
pause,
} = useLottieScrollTrigger({
// Disable React state tracking (default: false)
enableStateTracking: false,
// Monitor state through callbacks
onPlayStateChange: (isPlaying) => {
console.log('Play state changed:', isPlaying);
},
onFrameChange: (frame) => {
console.log('Frame changed:', frame);
// Update external state or UI (only when needed)
},
// Adjust frame update throttle (ms)
frameUpdateThrottle: 50, // default: 100ms
});
const handlePlayToggle = () => {
// Check current state via ref (no re-renders)
if (getIsPlaying()) {
pause();
} else {
play();
}
};
return (
<div ref={triggerRef}>
<DotLottieReact
src="/animation.lottie"
loop={false}
autoplay={false}
dotLottieRefCallback={handleDotLottieRef}
/>
<button onClick={handlePlayToggle}>
Play/Pause
</button>
<div>
{/* Get current frame via ref (no re-renders) */}
Current frame: {getCurrentFrame()}
</div>
</div>
);
}Scroll Progress Tracking
function ScrollProgress() {
const { triggerRef, handleDotLottieRef } = useLottieScrollTrigger({
start: "top center",
end: "bottom center",
// onScrollUpdate has been removed in v1.2.0
// Use callbacks like onEnter, onLeave instead
});
return (
<div ref={triggerRef} className="h-screen">
<DotLottieReact
src="/scroll-animation.lottie"
loop={false}
autoplay={false}
dotLottieRefCallback={handleDotLottieRef}
className="w-full h-full"
/>
</div>
);
}Safe Usage in SSR Environment
// Next.js App Router
export default function MyPage() {
const { triggerRef, handleDotLottieRef, isClient, isDOMReady, isLoaded } =
useLottieScrollTrigger({
strictMode: true, // Auto-enabled in SSR frameworks
waitForDOMReady: true, // Wait for complete DOM load
debug: true,
});
// Render only on client
if (!isClient || !isDOMReady) {
return <div>Loading...</div>;
}
return (
<div ref={triggerRef} className="h-screen">
<DotLottieReact
src="/animations/hero.lottie"
loop={false}
autoplay={false}
dotLottieRefCallback={handleDotLottieRef}
className="w-full h-full"
/>
</div>
);
}π¨ Framework Examples
This package includes complete example implementations for major React frameworks:
π± Next.js Example
Perfect for server-side rendering with App Router:
cd examples/nextjs-example
pnpm install
pnpm devFeatures:
- β App Router with SSR/CSR safety
- β Tailwind CSS styling
- β TypeScript configuration
- β Production-ready build
Key Implementation:
// app/page.tsx
import LottieScrollExample from "@/components/LottieScrollExample";
export default function Home() {
return <LottieScrollExample />;
}β‘ Vite Example
Lightning-fast development with modern tooling:
cd examples/vite-example
pnpm install
pnpm devFeatures:
- β Lightning-fast HMR
- β Optimized production build
- β TypeScript support
- β Modern bundling
π Remix Example
Full-stack framework with SSR capabilities:
cd examples/remix-example
pnpm install
pnpm devFeatures:
- β Server-side rendering
- β Progressive enhancement
- β TypeScript configuration
- β Tailwind CSS integration
π¦ React Router Example
Client-side routing with React Router 7:
cd examples/react-router-example
pnpm install
pnpm devFeatures:
- β React Router v7
- β File-based routing
- β Tailwind CSS 4.0
- β Vite build system
π― Common Example Features
All examples include:
- Scroll Trigger Animation: Smooth DotLottie animations triggered by scroll
- Play/Pause Controls: Manual animation control
- Debug Information: Real-time animation state display
- Responsive Design: Mobile-friendly layouts
- Performance Monitoring: Frame rate and state tracking
- Manual Control Mode: Toggle between scroll and manual control
π Example Code Structure
Each example follows this pattern:
export default function LottieScrollExample() {
const [externalPlayState, setExternalPlayState] = useState(false);
const [isManualControl, setIsManualControl] = useState(false);
const {
triggerRef,
handleDotLottieRef,
play,
pause,
isPlaying,
currentFrame,
isLoaded,
} = useLottieScrollTrigger({
start: "top 80%",
end: "bottom 20%",
debug: process.env.NODE_ENV === "development",
enableStateTracking: true,
onPlayStateChange: (isPlaying) => {
setExternalPlayState(isPlaying);
},
});
return (
<div className="min-h-screen bg-gradient-to-br from-purple-50 to-blue-50">
{/* Control Panel */}
<div className="fixed top-4 right-4 bg-white rounded-lg shadow-lg p-4">
<button
onClick={() => setIsManualControl(!isManualControl)}
className="mb-2 px-4 py-2 bg-blue-500 text-white rounded"
>
{isManualControl ? "Auto Mode" : "Manual Mode"}
</button>
{isManualControl && (
<div className="space-x-2">
<button
onClick={play}
className="px-3 py-1 bg-green-500 text-white rounded"
>
Play
</button>
<button
onClick={pause}
className="px-3 py-1 bg-red-500 text-white rounded"
>
Pause
</button>
</div>
)}
</div>
{/* Scroll Trigger Section */}
<div
ref={triggerRef}
className="h-screen flex items-center justify-center"
>
<div className="max-w-md w-full">
<DotLottieReact
src="/animations/sample.lottie"
loop={false}
autoplay={false}
dotLottieRefCallback={handleDotLottieRef}
className="w-full h-auto"
/>
</div>
</div>
{/* Status Display */}
<div className="p-8 text-center">
<p>Animation Status: {isLoaded ? "β
Loaded" : "β³ Loading..."}</p>
<p>Playing: {isPlaying ? "βΆοΈ Yes" : "βΈοΈ No"}</p>
<p>Current Frame: {currentFrame}</p>
</div>
</div>
);
}π API Reference
useLottieScrollTrigger(options)
Options
interface UseLottieScrollTriggerOptions {
// ScrollTrigger basic settings
start?: string; // default: "top center"
end?: string; // default: "bottom 20%"
markers?: boolean; // default: true only in development
pauseOnLoad?: boolean; // default: true
// Debugging
debug?: boolean; // default: false
debugLanguage?: "ko" | "en"; // default: "ko"
// SSR/CSR safety
strictMode?: boolean; // default: auto true in SSR frameworks
waitForDOMReady?: boolean; // default: auto true in SSR frameworks
// Performance optimization options (re-render control)
enableStateTracking?: boolean; // default: false (disable React state tracking)
frameUpdateThrottle?: number; // default: 100 (ms)
onPlayStateChange?: (isPlaying: boolean) => void; // Play state change callback
onFrameChange?: (currentFrame: number) => void; // Frame change callback
// DotLottie event callbacks
onEnter?: (dotLottie: DotLottie) => void;
onLeave?: (dotLottie: DotLottie) => void;
onEnterBack?: (dotLottie: DotLottie) => void;
onLeaveBack?: (dotLottie: DotLottie) => void;
// GSAP animations
gsapAnimations?: {
rotation?: number; // Rotation angle
scale?: number; // Scale factor
x?: number; // X-axis movement
y?: number; // Y-axis movement
opacity?: number; // Opacity
duration?: number; // Animation duration
ease?: string; // Easing function
trigger?: "enter" | "enterBack" | "leave" | "leaveBack" | "scroll";
scrub?: boolean | number; // Sync with scroll
};
// Additional ScrollTrigger options
scrollTriggerOptions?: Partial<ScrollTrigger.StaticVars>;
}Return Value
interface UseLottieScrollTriggerReturn {
// Required refs
triggerRef: React.RefObject<HTMLDivElement>;
handleDotLottieRef: (dotLottie: DotLottie | null) => void;
// DotLottie instance and state
dotLottie: DotLottie | null;
isDotLottieLoaded: boolean;
// Control functions
play: () => void;
pause: () => void;
stop: () => void;
setFrame: (frame: number) => void;
// Performance optimized state access
getCurrentFrame: () => number; // ref-based getter (no re-renders)
getIsPlaying: () => boolean; // ref-based getter (no re-renders)
// React state (updates only when enableStateTracking is true)
isPlaying: boolean; // always false if enableStateTracking is false
currentFrame: number; // always 0 if enableStateTracking is false
// Environment and loading state
isMounted: boolean;
isDOMReady: boolean;
isClient: boolean;
isLoaded: boolean;
isSSRFramework: boolean;
isNextJS: boolean;
isNuxt: boolean;
}β‘ Performance Optimization
Minimize Re-renders
By default, useLottieScrollTrigger disables React state tracking for performance:
// π High performance mode (default)
const { getCurrentFrame, getIsPlaying } = useLottieScrollTrigger({
enableStateTracking: false, // default
});
// Check state via ref (no re-renders)
console.log(getCurrentFrame()); // Current frame
console.log(getIsPlaying()); // Play stateSelective State Tracking
Enable only when you need to display animation state in UI:
// π― Track state only when needed
const { isPlaying, currentFrame } = useLottieScrollTrigger({
enableStateTracking: true, // Enable React state updates
frameUpdateThrottle: 200, // Limit frame updates to 200ms
onFrameChange: (frame) => {
// External state management or UI updates
setExternalState(frame);
},
});Callback-based State Monitoring
// π Performance optimization with callbacks
const { play, pause } = useLottieScrollTrigger({
enableStateTracking: false, // Prevent re-renders
onPlayStateChange: (isPlaying) => {
// Update external state only when needed
updateExternalPlayState(isPlaying);
},
onFrameChange: (frame) => {
// Update progress bar etc.
updateProgressBar(frame);
},
});Frame Update Throttling
const hook = useLottieScrollTrigger({
frameUpdateThrottle: 100, // default: 100ms (10fps)
// frameUpdateThrottle: 16, // For 60fps when needed
// frameUpdateThrottle: 50, // 20fps compromise
});Performance Monitoring
const hook = useLottieScrollTrigger({
debug: true, // Check performance logs in console
onFrameChange: (frame) => {
console.log(`Frame update: ${frame}`);
},
});π οΈ Troubleshooting
Common Issues
Q: Animation won't play
// 1. Check DotLottie load status
const { isLoaded, isDotLottieLoaded } = useLottieScrollTrigger({ debug: true });
// 2. Make sure autoplay is set to false
<DotLottieReact autoplay={false} />;
// 3. Check pauseOnLoad option
useLottieScrollTrigger({ pauseOnLoad: true }); // Pause after loadQ: Getting errors in SSR environment
// Enable strictMode and waitForDOMReady
const hook = useLottieScrollTrigger({
strictMode: true,
waitForDOMReady: true,
});
// Render only on client
if (!hook.isClient || !hook.isDOMReady) {
return <div>Loading...</div>;
}Q: ScrollTrigger not working
// 1. Check if triggerRef is properly set
<div ref={triggerRef}>
<DotLottieReact dotLottieRefCallback={handleDotLottieRef} />
</div>
// 2. Verify GSAP is correctly installed
npm list gsap
// 3. Debug the issue with debug mode
useLottieScrollTrigger({ debug: true, markers: true })π€ Contributing
- Fork this repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
π License
MIT License - see the LICENSE file for details.
π Acknowledgments
- @lottiefiles/dotlottie-react - Excellent DotLottie React component
- GSAP - Powerful animation library
- All contributors in the React community
π‘ For more examples and documentation, visit the GitHub Repository!
