Hover Trigger
Play animations on mouse enter with reverse or restart on leave.
.onHover() plays a timeline when the pointer enters a target element and reacts when the pointer leaves — reversing, restarting, or doing nothing based on your configuration.
Basic usage
Chain .onHover() after defining your animation. By default, leaving the element does nothing. Pass onLeave: 'reverse' to smoothly reverse back to the start state.
Options
| Option | Type | Default | Description |
|---|---|---|---|
each | boolean | false | Create an independent timeline instance per matched element. |
onLeave | 'reverse' | 'restart' | 'none' | 'none' | What to do when the pointer leaves the element. |
onLeave behavior
Control what happens when the pointer leaves the element:
'reverse'(recommended) — smoothly plays the timeline in reverse back to the start state.'restart'— snaps immediately to the start state and replays the animation forward.'none'(default) — does nothing; the animation stays at its end state after hover.
// Smoothly reverses on leave — feels natural for most hover effects
Motion("btn", ".btn", {
to: { scale: 1.05, backgroundColor: "#7744FF" },
duration: 0.25,
ease: "power2.out",
}).onHover({ onLeave: "reverse" });
// Snaps back and replays — good for looping-style feedback
Motion("badge", ".badge", {
to: { rotate: 10 },
duration: 0.2,
}).onHover({ onLeave: "restart" });
// Stays at end state — useful when hover reveals persistent UI
Motion("tooltip", ".tooltip", {
from: { opacity: 0, y: 4 },
duration: 0.2,
}).onHover({ onLeave: "none" }); each — independent per-element instances
When a selector matches multiple elements, all elements share one timeline by default — hovering any one of them plays the animation for all. Use each: true to give every element its own independent timeline instance.
// Without each — hovering any card affects all cards simultaneously
Motion("cards", ".card", {
to: { y: -8 },
duration: 0.3,
}).onHover({ onLeave: "reverse" });
// With each — each card responds independently
Motion("cards", ".card", {
to: { y: -8 },
duration: 0.3,
}).onHover({ each: true, onLeave: "reverse" }); each: true is almost always what you want when the selector targets a list of interactive items like cards, buttons, nav links, or gallery items.
Card lift with shadow
Motion("card-hover", ".card", {
to: { y: -8, boxShadow: "0 12px 24px rgba(0,0,0,0.15)" },
duration: 0.3,
ease: "power2.out",
}).onHover({ each: true, onLeave: "reverse" }); Scale on hover
Motion("scale-hover", ".thumb", {
to: { scale: 1.06 },
duration: 0.25,
ease: "power2.out",
}).onHover({ each: true, onLeave: "reverse" }); Background color change
Motion("color-hover", ".nav-link", {
to: { backgroundColor: "#f0ebff", color: "#6633EE" },
duration: 0.2,
ease: "power1.out",
}).onHover({ each: true, onLeave: "reverse" }); Reveal an overlay on hover
Motion("overlay-hover", ".gallery-item", {
to: { opacity: 1 },
duration: 0.3,
ease: "power2.out",
}).onHover({ each: true, onLeave: "reverse" }); Staggered grid ripple on hover
Motion("grid-hover", ".cell", {
to: { scale: 1.1, backgroundColor: "#6633EE" },
duration: 0.3,
stagger: {
each: 0.03,
from: "center",
grid: "auto",
},
ease: "power2.out",
}).onHover({ onLeave: "reverse" }); Using to for hover effects
Hover effects typically use to rather than from — the element starts at its natural CSS state and animates to the hover state. The SDK reads the current computed styles as the from automatically.
// ✅ to-only — starts at natural state, animates to hover values
Motion("btn-hover", ".btn", {
to: { scale: 1.08, letterSpacing: "0.05em" },
duration: 0.25,
ease: "power2.out",
}).onHover({ each: true, onLeave: "reverse" });
// ❌ Unnecessary — natural defaults (scale: 1) don't need to be declared in from
Motion("btn-hover", ".btn", {
from: { scale: 1 },
to: { scale: 1.08 },
duration: 0.25,
}).onHover({ each: true, onLeave: "reverse" }); Related
- Click Trigger — toggle animations on click
- Mouse Movement — animate based on cursor position
- Scroll Trigger — trigger animations on scroll