Hover animations are the most common form of gesture animation.
Motion improves on the CSS :hover psuedo-class, which can cause frustrating "sticky" states on touch devices, where hover styles can persist after a user lifts their finger.
Motion provides three powerful methods to tap into hover gestures to create reliable, cross-device hover interactions that filter out these unwanted emulated events:
-
The
whileHoveranimation prop -
onHoverevents -
hover()gesture recogniser
In this guide, we'll take a look at how (and when) to use each.
The whileHover prop
The simplest and most common way to add a hover animation with Motion is with the motion component's whileHover prop.
It's a declarative way to define a target animation state - when a hover gesture starts, the component will animate to the values defined in it, and when the gesture ends, it'll animate back to its previous state.
<motion.button whileHover={{ scale: 1.1 }} />Customise the animation
Transitions can be defined for when we enter a hover gesture state by setting transition within the whileHover definition.
<motion.button
whileHover={{
scale: 1.1,
// Will be used when gesture starts
transition: { duration: 0.1 }
}}
// Will be used when gesture ends
transition={{ duration: 0.5 }}
/>450+ production-ready examples.
JavaScript, React, and Vue. Copy and paste straight into your project, adapt with AI, or pipe the whole set into your agent with the Examples MCP.
Event handlers
You can also listen for when a hover gesture starts and ends with the onHoverStart and onHoverEnd events.
<motion.a
onHoverStart={() => console.log('Hover starts')}
onHoverEnd={() => console.log('Hover ends')}
/>These events differ from the browser's native pointer event handling by only firing on devices where hover is truly possible. They explicitly won't fire as the result of a touch event.
hover() gesture recogniser
To use onHoverStart and onHoverEnd, you need to import the full motion component. For lightweight hover gesture handling, you can import the tiny (<1kb) hover() function.
Because it returns a cleanup function, it's straightforward to integrate with useEffect:
import { hover } from "motion"
import { useRef, useEffect } from "react"
function Component() {
const ref = useRef(null)
useEffect(() => {
return hover(ref.current, () => {
console.log("on hover start")
return () => console.log("on hover end")
})
}, [])
return <button ref={ref} />
}Stay in the loop.
Deep dives on animation, performance, and building Motion. New issues land roughly once a month, no filler.
