API reference
Full prop reference for DrawIcon and MotionIconConfig.
Icon components
Every Lucide icon is exported as a React component:
import { Heart, HeartIcon } from "lucide-react-motion";
// ^^^^^ ^^^^^^^^^
// Both names point to the same component.Each icon accepts the props below. Generated icon files are thin wrappers around <DrawIcon />, so their prop type is Omit<DrawIconProps, "nodes" | "iconName" | "signature"> — the wrapper supplies all three. Each icon also exports its own alias for that type (HeartProps, SettingsProps, …).
DrawIcon props
Lucide-parity props
| Prop | Type | Default | Notes |
|---|---|---|---|
size | number | 24 | Pixel size of the rendered SVG |
color | string | "currentColor" | Stroke color (inherits parent CSS color by default) |
strokeWidth | number | 2 | Line thickness |
absoluteStrokeWidth | boolean | false | Keep stroke pixel-constant regardless of size |
className, style | — | — | Standard React attributes, spread onto the underlying <svg> |
onClick, aria-*, data-* | — | — | All standard SVG attributes are forwarded |
ref | Ref<MotionIconHandle> | — | Imperative handle (see trigger="manual") |
Timing props
See Animation for live demos.
| Prop | Type | Default | Notes |
|---|---|---|---|
duration | number | 0.55 | Seconds per stroke |
delay | number | 0 | Seconds before draw starts |
stagger | number | 0.12 | Per-stroke delay increment |
easing | Easing or Easing[] | "easeInOut" | Motion easing curve |
repeat | number | 0 | Extra repetitions. Infinity = loop |
Behavior props
| Prop | Type | Default | Notes |
|---|---|---|---|
trigger | Trigger | "hover" | When/how the animation fires. See Triggers. |
onLeave | OnLeave | "complete" | What happens when trigger ends. See Leave behavior. |
reducedMotion | ReducedMotion | "system" | Respect / force / disable reduced-motion. See Accessibility. |
mode | ModeName or ModeFactory | "draw" | Which animation to play. See Modes. |
Escape hatch
| Prop | Type | Notes |
|---|---|---|
variants | Variants or (i: number) => Variants | Bypass mode and supply Motion variants directly. See Custom motion. |
<DrawIcon />-only props
Generated icon components fill these in, so you only pass them when rendering <DrawIcon /> directly with raw Lucide node data.
| Prop | Type | Default | Notes |
|---|---|---|---|
nodes | IconNode[] | — | Required. The Lucide icon-node array to render. |
iconName | string | "" | Lucide name of the icon. Used for dev warnings and signature lookup. |
signature | Mode | — | The mode played when mode="signature". Supply your own to make an arbitrary node set respond to it. |
DOM attributes the engine writes
The rendered <svg> also carries an attribute that the engine owns. It is read-only from a consumer's perspective — passing it as a prop has no effect.
| Attribute | Values | Notes |
|---|---|---|
data-motion-state | "resting" | "drawing" | Whether the stroke draw is currently animating. See Motion state. |
Type definitions
type Trigger =
| "hover"
| "click"
| "mount"
| "in-view"
| "parent-hover"
| "manual";
type OnLeave = "complete" | "snap" | "redraw";
type ReducedMotion = "system" | "always" | "never";
type MotionState = "resting" | "drawing";
type ModeName = "draw" | "signature";
interface ModeContext {
iconName: string;
index: number;
pathTag: string; // "path" | "circle" | "rect" | "line" | …
pathAttrs: Record<string, string | number>; // the element's attrs (incl. `d`)
duration: number;
delay: number;
stagger: number;
easing: Easing | Easing[];
repeat: number;
pathLength: number; // engine-measured, from getTotalLength()
}
type ModeFactory = (ctx: ModeContext) => Variants;
interface ModeDefaults {
duration?: number;
delay?: number;
stagger?: number;
easing?: Easing | Easing[];
repeat?: number;
}
interface Mode {
factory: ModeFactory;
defaults?: ModeDefaults;
needsTransformOrigin?: boolean; // engine sets transform-origin on each child
transformOrigin?: string; // override the pivot (default "12px 12px")
}
interface MotionIconHandle {
play: () => void;
reset: () => void;
node: SVGSVGElement | null;
}
type IconNode = [tag: string, attrs: Record<string, string | number>];All exported from lucide-react-motion.
MotionIconConfig
React Context provider for app-wide defaults. See App-wide defaults.
interface MotionIconConfigValue {
size?: number;
color?: string;
strokeWidth?: number;
absoluteStrokeWidth?: boolean;
duration?: number;
delay?: number;
stagger?: number;
easing?: Easing | Easing[];
repeat?: number;
trigger?: Trigger;
onLeave?: OnLeave;
reducedMotion?: ReducedMotion;
mode?: ModeName | ModeFactory;
}
function MotionIconConfig(
props: MotionIconConfigValue & { children: ReactNode }
): JSX.Element;Other exports
import {
DrawIcon, // The animated SVG primitive every icon wraps.
MotionIconConfig, // Context provider for defaults.
PARENT_HOVER_ATTR, // = "data-motion-icon-group"
type DrawIconProps,
type IconNode,
type Mode,
type ModeContext,
type ModeDefaults,
type ModeFactory,
type ModeName,
type MotionIconConfigValue,
type MotionIconHandle,
type MotionState,
type OnLeave,
type ReducedMotion,
type Trigger,
} from "lucide-react-motion";Manifest
The package publishes a metadata list of every icon under the lucide-react-motion/manifest subpath. It's handy for building galleries and search — it carries no React/Motion code, just data.
import { manifest, type ManifestEntry } from "lucide-react-motion/manifest";
interface ManifestEntry {
name: string; // lucide kebab name, e.g. "message-circle-dashed"
component: string; // PascalCase export name, e.g. "MessageCircleDashed"
tags: readonly string[]; // lucide search/category tags
hasSignature: boolean; // true if mode="signature" plays a bespoke animation
// (false → it falls back to mode="draw")
}
const manifest: ManifestEntry[];// Example: build a searchable gallery from the manifest.
import { manifest } from "lucide-react-motion/manifest";
const results = manifest.filter((m) => m.name.includes(query));hasSignature is true for every entry today — signature coverage is complete. The field stays on the manifest as a forward guard: if Lucide publishes a brand-new icon before its signature lands, that entry reports false and your UI can branch on it without a release of its own.