react-tooltip: [BUG] Tooltip position and show status not synchronized.
Describe the bug When moving from one anchor to another, sometimes the tooltip’s position is updated before its visibility. This results in some glitchy / flickering behavior.
Version of Package v5.10.6
To Reproduce
- Set
Tooltip
delayShow
to300
- Set
Tooltip
delayHide
to0
- Move from one anchor to another (with no space between)
- Observe that the tooltip first changes position and content, then hides. Then after 300ms shows again.
Expected behavior The tooltip should hide first, then update position and content.
Screenshots https://user-images.githubusercontent.com/431251/230918927-995f1ccf-2449-40d8-8a4b-948c48605393.mp4
Desktop (please complete the following information if possible or delete this section):
- OS: MacOS
- Browser firefox
- Version [e.g. 22]
- Frameworks
create-react-app
Additional context Repro: https://github.com/knubie/react-tooltip-demo Somewhat, but not really related: https://github.com/ReactTooltip/react-tooltip/issues/1008
About this issue
- Original URL
- State: open
- Created a year ago
- Reactions: 2
- Comments: 29 (12 by maintainers)
This one will be a lot trickier to solve. The root of this problem is that the tooltip content and the tooltip position are updated independently. Since the position calculation may take more than 1 render cycle to finish, and updating the content will pretty much always take exactly 1 cycle, sometimes you’ll see the text updating before the position.
We’ve tried to fix this by updating the content and the position on the same cycle 100% of the time, but it turned out to be not that easy.
The tooltip closing when you move from one element to another is actually a bug, since the expected behavior when using
delayShow
is that the tooltip will stay open for as long as you’re hovering an anchor element, not close and reopen after the delay.Here are some alternatives until we can tackle this on (it might take several days until we have the time):
delayShow
, also usedelayHide
with a small value (50
should be fine). This will mitigate the flickering, though sometimes you’ll still see the text updating before the tooltip has moved.If you have any other ideas, please let us know.
@danielbarion we could try, but I’m guessing it won’t work.
my bet is on some weird CSS specification that safari doesn’t follow exactly as it should. maybe something to so with how opacity transition is behaving
Thanks for taking the time.
Another interesting thing to notice is how the opacity does not seem to transition properly (fade in on open) sometimes. I believe this is directly related. We’ll investigate further.
Just as a heads up, I believe a recent update in the way we inject the tooltip styling into the app broke setting the opacity like this. We’ll be looking into this soon.
Closing #1051 should help with this.
@dbidwell94 please try the following setup:
Setting
opacity: 1
on the tooltip styling breaks funcionality. The correct way to set the opacity is by overriding the CSS variable like this:(As a side-note, we should probably add a more straight-forward way of setting the opacity, such as an
opacity
prop.)I’ve also set
positionStrategy="fixed"
since the scrollbar was showing for a frame when the tooltip is inserted into the DOM. Please see if this works for you.@knubie Please confirm if you’re setting
opacity: 1
manually.Ah okay. I was going to ask about this earlier. Solving that bug might be a good next step.
This worked for me. However I noticed another issue that is kind of the opposite of the previous one: When hovering over an anchor, the tooltip’s
show
state is updated totrue
first, then a frame or two later the position and content are updated. This has the effect of the tooltip showing up at it’s previous position for a frame or two before moving to the correct position. However I was only able to replicate this in my own application and not the create-react-app demo.To resolve that I simply added the
transition
CSS property back in so that the tooltip isopacity: 0
for the first frame or two.Ideally all of the state change (show/position/content) should update synchronously. I don’t have any concrete suggestions for you at the moment, though, as I’m not that familiar with the code base.