Skip to content

[BUG] whileHover/whileTap gesture state gets stuck after Fast Refresh when reordering sibling motion.divs #3787

Description

@AnuragSapra

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:

  1. Hovering scales the element to 1.2, but moving the pointer away leaves it at 1.2.
  2. Clicking (near the edge so that whileTap scaling causes the pointer to go outside hover range) can leave the element stuck at an intermediate scale (~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.

  1. Open the CodeSandbox reproduction
  2. Start the development server.
  3. Reorder the two sibling motion.div components in App.jsx.
  4. Save the file so Fast Refresh occurs.
  5. Hover over the box and move the pointer away.
  6. Observe that the box remains at scale(1.2) instead of returning to scale(1).
  7. Click near the edge of the stuck element so that the pointer is outside the element when it shrinks during whileTap.
  8. 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 whileHover and whileTap props.
  • When the element is visually stuck, $0.matches(":hover") returns false, 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.div using initial and animate. I was unable to reproduce the bug when those props were removed or replaced with gesture props. Restoring initial and animate made the issue reproducible again.

Video

motion-hmr-hover-state-bug.1.mp4

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions