motiondivision / motiondivision/motion
[BUG] whileHover/whileTap gesture state gets stuck after Fast Refresh when reordering sibling motion.divs
Nobody has claimed this yet.
- 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:
- 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
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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