[BUG] whileHover/whileTap gesture state gets stuck after Fast Refresh when reordering sibling motion.divs
Environment
OS: Windows 11 Browser: Chrome Browser version: 150.0.7871.187 (Stable)
Motion: 12.43.0 React: 19.2.8 React DOM: 19.2.8 Vite: 8.2.0
NOTE : The issue was originally discovered with Motion 12.43.0. I have also reproduced the same behavior in a separate reproduction (attached video) using Motion 13.0.0 and in the CodeSandbox reproduction.
Summary
After a Fast Refresh (HMR) triggered by reordering (cut/paste) two sibling motion.div components, gesture animations can become stuck.
The affected element no longer returns to its idle state after whileHover or whileTap interactions. For example:
- Hovering scales the element to 1.2, but moving the pointer away leaves it at 1.2.
- Clicking (near the edge so that
whileTapscaling causes the pointer to go outside hover range) can leave the element stuck at an intermediatescale(~0.78) instead of returning to its idle scale.
This only occurs during development after a Fast Refresh. A full page refresh immediately restores the expected behavior.
Minimal reproduction (CodeSandbox)
https://codesandbox.io/p/sandbox/motion-hmr-repro-3ndn5l
Steps to reproduce
The issue is reproducible consistently using the steps below.
- Open the CodeSandbox reproduction
- Start the development server.
- Reorder the two sibling
motion.divcomponents inApp.jsx. - Save the file so Fast Refresh occurs.
- Hover over the box and move the pointer away.
- Observe that the box remains at
scale(1.2)instead of returning toscale(1). - Click near the edge of the stuck element so that the pointer is outside the element when it shrinks during
whileTap. - Observe that the element can become stuck at an intermediate
scale(~0.78).
Expected behavior
After the pointer leaves the element, whileHover should end and the element should return to its idle state.
After a tap completes, whileTap should end and the element should return to its idle state.
Fast Refresh should not leave gesture animations in a persistent state.
Additional observations
- React DevTools continues to show the expected
whileHoverandwhileTapprops. - When the element is visually stuck,
$0.matches(":hover")returnsfalse, indicating the browser no longer considers the element hovered even though the hover transform is still applied. - The issue appears to depend on a sibling
motion.divusinginitialandanimate. I was unable to reproduce the bug when those props were removed or replaced with gesture props. Restoringinitialandanimatemade the issue reproducible again.
Video
https://github.com/user-attachments/assets/56bc51c0-25a1-4631-b277-58e3d6e87775
Source: motiondivision/motion