Lucide Motion

Triggers

Six ways to fire the animation - hover, click, mount, in-view, parent-hover, manual.

The trigger prop selects when the animation fires. Default is "hover".

<Heart trigger="hover" />       // default
<Heart trigger="click" />
<Heart trigger="mount" />
<Heart trigger="in-view" />
<Heart trigger="parent-hover" />
<Heart trigger="manual" />

hover (default)

Animation plays while the cursor is over the icon. Standard behavior.

<Heart trigger="hover" />

On touch devices there's no hover. Use click or mount for mobile-friendly motion.


click

Replays the draw on every click. The cursor changes to pointer automatically.

<Bell trigger="click" />

Useful for action confirmations: success checkmarks, "added to cart," etc.


mount

Animates once on first paint. Great for hero icons or page intros.

<Star trigger="mount" />

Refresh the page to see it again. Combine with delay to stagger multiple mount-triggered icons:

<Heart trigger="mount" delay={0} />
<Star trigger="mount" delay={0.2} />
<Bell trigger="mount" delay={0.4} />

in-view

Animates each time the icon scrolls into the viewport. Built on IntersectionObserver. Scroll the demo out of view and back in to see it replay.

<Zap trigger="in-view" />

Useful for landing pages where icons should animate as the user scrolls down.


parent-hover

Animate the icon when a parent element is hovered, not just the icon itself. This is the trigger you want for icons inside buttons or cards.

How it works: the icon walks up the DOM to find the nearest ancestor with data-motion-icon-group and binds to its hover events.

<button
  data-motion-icon-group
  className="inline-flex items-center gap-2 rounded-md bg-zinc-900 px-4 py-2 text-white"
>
  Continue
  <Send size={18} trigger="parent-hover" />
</button>

You can use any element as the group root — <button>, <a>, <div>, <li>. The constant PARENT_HOVER_ATTR is also exported from the package if you'd rather reference it programmatically.


manual

You control when the animation fires via an imperative ref. The ref exposes a MotionIconHandle:

interface MotionIconHandle {
  play: () => void;
  reset: () => void;
  node: SVGSVGElement | null;
}
"use client";
import { useRef } from "react";
import { Rocket } from "lucide-motion";
import type { MotionIconHandle } from "lucide-motion";

export function LaunchButton() {
  const iconRef = useRef<MotionIconHandle>(null);

  return (
    <div className="flex items-center gap-4">
      <Rocket size={48} trigger="manual" ref={iconRef} />
      <button onClick={() => iconRef.current?.play()}>
        Launch
      </button>
    </div>
  );
}

Use this for animations driven by external events — form submission success, route transitions, websocket messages, etc.


Choosing a trigger

GoalTrigger
Default delightful hoverhover
Replay on action / mobile-friendlyclick
Hero / page-load animationmount
Scroll-driven revealin-view
Animate icon inside a buttonparent-hover
External-event-drivenmanual

On this page