Lucide React Motion

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

PropTypeDefaultNotes
sizenumber24Pixel size of the rendered SVG
colorstring"currentColor"Stroke color (inherits parent CSS color by default)
strokeWidthnumber2Line thickness
absoluteStrokeWidthbooleanfalseKeep stroke pixel-constant regardless of size
className, styleStandard React attributes, spread onto the underlying <svg>
onClick, aria-*, data-*All standard SVG attributes are forwarded
refRef<MotionIconHandle>Imperative handle (see trigger="manual")

Timing props

See Animation for live demos.

PropTypeDefaultNotes
durationnumber0.55Seconds per stroke
delaynumber0Seconds before draw starts
staggernumber0.12Per-stroke delay increment
easingEasing or Easing[]"easeInOut"Motion easing curve
repeatnumber0Extra repetitions. Infinity = loop

Behavior props

PropTypeDefaultNotes
triggerTrigger"hover"When/how the animation fires. See Triggers.
onLeaveOnLeave"complete"What happens when trigger ends. See Leave behavior.
reducedMotionReducedMotion"system"Respect / force / disable reduced-motion. See Accessibility.
modeModeName or ModeFactory"draw"Which animation to play. See Modes.

Escape hatch

PropTypeNotes
variantsVariants or (i: number) => VariantsBypass 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.

PropTypeDefaultNotes
nodesIconNode[]Required. The Lucide icon-node array to render.
iconNamestring""Lucide name of the icon. Used for dev warnings and signature lookup.
signatureModeThe 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.

AttributeValuesNotes
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.

On this page