Documentation Index Fetch the complete documentation index at: https://mintlify.com/pqoqubbw/icons/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Lucide Animated icons are built as React components that combine Lucide SVG icons with Framer Motion animations. Each icon component follows a consistent architecture pattern that enables both automatic hover animations and programmatic control.
Core Architecture
Every icon component in Lucide Animated follows this structure:
'use client' ;
import { useAnimation } from 'motion/react' ;
import type { HTMLAttributes } from 'react' ;
import { forwardRef , useCallback , useImperativeHandle , useRef } from 'react' ;
import { cn } from '@/lib/utils' ;
export interface [ IconName ] Handle {
startAnimation : () => void ;
stopAnimation : () => void ;
}
interface [ IconName ] Props extends HTMLAttributes < HTMLDivElement > {
size ?: number ;
}
const [ IconName ] = forwardRef < [ IconName ] Handle , [ IconName ]Props>(
({ onMouseEnter , onMouseLeave , className , size = 28 , ... props }, ref ) => {
const controls = useAnimation ();
const isControlledRef = useRef ( false );
useImperativeHandle ( ref , () => {
isControlledRef . current = true ;
return {
startAnimation : () => controls . start ( 'animate' ),
stopAnimation : () => controls . start ( 'normal' ),
};
});
const handleMouseEnter = useCallback (
( e : React . MouseEvent < HTMLDivElement >) => {
if ( isControlledRef . current ) {
onMouseEnter ?.( e );
} else {
controls . start ( 'animate' );
}
},
[ controls , onMouseEnter ]
);
const handleMouseLeave = useCallback (
( e : React . MouseEvent < HTMLDivElement >) => {
if ( isControlledRef . current ) {
onMouseLeave ?.( e );
} else {
controls . start ( 'normal' );
}
},
[ controls , onMouseLeave ]
);
return (
< div
className = { cn ( className ) }
onMouseEnter = { handleMouseEnter }
onMouseLeave = { handleMouseLeave }
{ ... props }
>
< motion.svg
animate = { controls }
fill = "none"
height = { size }
stroke = "currentColor"
strokeLinecap = "round"
strokeLinejoin = "round"
strokeWidth = "2"
variants = { {
normal: { scale: 1 },
animate: { scale: [ 1 , 1.08 , 1 ] },
} }
viewBox = "0 0 24 24"
width = { size }
xmlns = "http://www.w3.org/2000/svg"
>
{ /* SVG paths */ }
</ motion.svg >
</ div >
);
}
);
[ IconName ]. displayName = '[IconName]' ;
export { [ IconName ] };
Key Components
Dual-Mode System
Each icon supports two operating modes:
Uncontrolled Mode Default behavior - animations trigger automatically on hover
Controlled Mode Programmatic control via ref - animations triggered by startAnimation() and stopAnimation() methods
Animation Control Flow
The isControlledRef pattern determines which mode the icon operates in:
const isControlledRef = useRef ( false );
useImperativeHandle ( ref , () => {
isControlledRef . current = true ; // Switches to controlled mode
return {
startAnimation : () => controls . start ( 'animate' ),
stopAnimation : () => controls . start ( 'normal' ),
};
});
When a ref is attached, isControlledRef.current becomes true, disabling automatic hover animations.
Mouse Event Handlers
The handlers check the control mode before triggering animations:
const handleMouseEnter = useCallback (
( e : React . MouseEvent < HTMLDivElement >) => {
if ( isControlledRef . current ) {
onMouseEnter ?.( e ); // Pass through to parent
} else {
controls . start ( 'animate' ); // Auto-animate
}
},
[ controls , onMouseEnter ]
);
Animation with Framer Motion
All animations use Framer Motion’s motion components and useAnimation hook:
Simple Animation Example
From heart.tsx:61-82:
< motion.svg
animate = { controls }
variants = { {
normal: { scale: 1 },
animate: { scale: [ 1 , 1.08 , 1 ] },
} }
transition = { {
duration: 0.45 ,
repeat: 2 ,
} }
>
< path d = "M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z" />
</ motion.svg >
Complex Multi-Element Animation
From smile.tsx:109-157:
< motion.svg variants = { faceVariants } >
< motion.circle cx = "12" cy = "12" r = "10" />
< motion.path
variants = { mouthVariants }
d = "M8 14s1.5 2 4 2 4-2 4-2"
/>
< motion.line
variants = { eyeVariants }
x1 = "9" x2 = "9.01" y1 = "9" y2 = "9"
/>
</ motion.svg >
Different elements can have independent variant definitions for coordinated animations.
Multiple Animation Controls
Some icons use multiple useAnimation() instances for complex choreography.
From sparkles.tsx:54-70:
const starControls = useAnimation ();
const sparkleControls = useAnimation ();
return {
startAnimation : () => {
sparkleControls . start ( 'hover' );
starControls . start ( 'blink' , { delay: 1 });
},
stopAnimation : () => {
sparkleControls . start ( 'initial' );
starControls . start ( 'initial' );
},
};
Variants Pattern
Variants define animation states. They can be defined inline or as constants:
// Inline variants
const variants = {
normal: { scale: 1 },
animate: { scale: [ 1 , 1.08 , 1 ] },
};
// Constant variants (typed)
const SVG_VARIANTS : Variants = {
normal: { rotate: 0 },
animate: { rotate: [ 0 , - 10 , 10 , - 10 , 0 ] },
};
Design Principles
Consistency All icons follow the same structural pattern for predictable behavior
Flexibility Support both automatic and manual animation control
Composition Built with standard React patterns (forwardRef, useImperativeHandle)
Performance Use useCallback for memoized event handlers
Template Structure
When creating new icons, follow this template from CONTRIBUTING.md:
Client Component Directive : Start with 'use client';
Type Definitions : Export [IconName]Handle interface and props interface
Component Implementation : Use forwardRef with proper typing
Animation Setup : Initialize useAnimation() and isControlledRef
Ref Handling : Implement useImperativeHandle for control API
Event Handlers : Create memoized mouse event callbacks
Render : Return wrapper div with motion.svg and animation variants
Display Name : Set component displayName for debugging
This consistent structure ensures all icons work seamlessly with both usage patterns.