motiondivision / motiondivision/motion

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

Open
#3,787 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
33.7k
Forks
1.4k
Avg merge
1d 10h
Merged PRs (30d)
14

Description

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

https://github.com/user-attachments/assets/56bc51c0-25a1-4631-b277-58e3d6e87775

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the CodeSandbox reproduction and App.jsx, then inspect how sibling motion.div elements using initial and animate interact with whileHover and whileTap during Fast Refresh. Reproduce the reorder, save, and pointer interactions; done means both gestures consistently return to the idle scale after refresh, pointer exit, and tap completion.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.