Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Tooltip position and show status not synchronized. #1010

Open
knubie opened this issue Apr 10, 2023 · 29 comments
Open

[BUG] Tooltip position and show status not synchronized. #1010

knubie opened this issue Apr 10, 2023 · 29 comments
Labels
Bug Help Wanted V6 It might get fixed/merged before, but most likely only on V6's release.

Comments

@knubie
Copy link

knubie commented Apr 10, 2023

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

  1. Set Tooltip delayShow to 300
  2. Set Tooltip delayHide to 0
  3. Move from one anchor to another (with no space between)
  4. 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: #1008

@gabrieljablonski
Copy link
Member

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):

  1. When using delayShow, also use delayHide 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.
  2. Use one tooltip for each anchor element. This is really not ideal, and we usually recommend against this, but it could work on your case if you don't have many elements (anything up to 20 tooltips on the page should be fine, maybe even more).

If you have any other ideas, please let us know.

@knubie
Copy link
Author

knubie commented Apr 10, 2023

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.

Ah okay. I was going to ask about this earlier. Solving that bug might be a good next step.

  1. When using delayShow, also use delayHide 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.

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 to true 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 is opacity: 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.

@github-actions
Copy link

This issue is stale because it has not seen activity in 30 days. Remove the stale label or comment within 14 days, or it will be closed.

@github-actions github-actions bot added the Stale This has not seen activity in quite some time label May 12, 2023
@gabrieljablonski gabrieljablonski removed the Stale This has not seen activity in quite some time label May 12, 2023
@dbidwell94
Copy link

I'm experiencing a similar issue.

reactTooltipBug.mp4

Looks like the position is not updated before the tooltip is shown

@knubie
Copy link
Author

knubie commented Jul 1, 2023

Also experiencing this on the latest version, even with the transition hack mentioned above. Haven't had time to dig into how or why it's happening, though.

@dbidwell94
Copy link

I've been digging, but I can't seem to find the problem yet.

@gabrieljablonski
Copy link
Member

@dbidwell94 the original issue has to do with transitioning between two adjancent anchor elements, yours seems to be a little different. I am unable to reproduce it. If you could provide a sample repo it would help a lot.

@knubie are you experiencing the same thing? as in:

  • you hover on an element to show the tooltip
  • you hover out and the tooltip is hidden
  • you hover on another element and the tooltip is misplaced for a few frames

Again, I haven't been able to reproduce this.

@knubie
Copy link
Author

knubie commented Jul 1, 2023

Just recorded a demo video from my production app. I noticed the following things:

  • On mouseout the tooltip is misplaced for a few frames.
  • On mouseenter the tooltip is misplaced for ~1 frame sometimes. This only happens once or twice in the video.

Here are the settings for my tooltip:

delay-show = 500
delay-hide = 50
transition: opacity 0.1s ease-out
tooltip_bug4.mp4

@dbidwell94
Copy link

@gabrieljablonski Here are the items in question:

React tooltip instance => https://github.com/Tekxchange/web_ui/blob/master/src/App.tsx#L26

Go to current location data-id => https://github.com/Tekxchange/web_ui/blob/master/src/pages/app/map/index.tsx#L86
Results bar id => https://github.com/Tekxchange/web_ui/blob/master/src/pages/app/resultsBar/index.tsx#L41

I'm not sure it's too big of a deal. While testing I have noticed it:

A) only seems to happen on Opera (might happen on Safari as well, I'm not sure)
B) only happens on that browser if you are logged in
C) Chrome and Firefox seem to be working as expected.

@gabrieljablonski
Copy link
Member

@dbidwell94 thanks for taking the time. We'll investigate and see what we can do.

@gabrieljablonski
Copy link
Member

@dbidwell94 please try the following setup:

<ReactTooltip
  id="tooltip"
  delayShow={1000}
  positionStrategy="fixed"
  style={{ zIndex: 1000 }}
/>

Setting opacity: 1 on the tooltip styling breaks funcionality. The correct way to set the opacity is by overriding the CSS variable like this:

:root {
  --rt-opacity: 1;
}

(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.

@gabrieljablonski
Copy link
Member

gabrieljablonski commented Jul 2, 2023

:root {
  --rt-opacity: 1;
}

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
Copy link

@dbidwell94 please try the following setup:

<ReactTooltip
  id="tooltip"
  delayShow={1000}
  positionStrategy="fixed"
  style={{ zIndex: 1000 }}
/>

Setting opacity: 1 on the tooltip styling breaks funcionality. The correct way to set the opacity is by overriding the CSS variable like this:

:root {
  --rt-opacity: 1;
}

(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.

Looks like this does indeed solve my problem. Thanks for getting back to me so quick!

@knubie
Copy link
Author

knubie commented Jul 3, 2023

@dbidwell94 please try the following setup:

<ReactTooltip
  id="tooltip"
  delayShow={1000}
  positionStrategy="fixed"
  style={{ zIndex: 1000 }}
/>

Setting opacity: 1 on the tooltip styling breaks funcionality. The correct way to set the opacity is by overriding the CSS variable like this:

:root {
  --rt-opacity: 1;
}

(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.

I can confirm that I'm not setting opacity: 1 manually. I just updated everything in my code to the default settings and am still seeing the issue. It does appear, though, that this bug only affects one or two components, so there must be something peculiar about them that's causing this issue.

@knubie
Copy link
Author

knubie commented Jul 3, 2023

Okay 😓 So i figured out the issue. It turns out that the bar under the numbers also has a tooltip, and so when I was moving the cursor out of the first tooltip anchor, i was briefly hovering over the bar, which caused it's tooltip to be displayed. So I think everything is working as intended. I will close this issue now.

@knubie knubie closed this as completed Jul 3, 2023
@gabrieljablonski
Copy link
Member

gabrieljablonski commented Jul 3, 2023

I'll reopen this since the original issue isn't actually fixed.

For future reference, the behavior in the first video in this issue is indeed a bug: https://user-images.githubusercontent.com/431251/230918927-995f1ccf-2449-40d8-8a4b-948c48605393.mp4

If anyone is experiencing this, refer to my earlier comment, which suggests using delayHide alongside delayShow to mitigate the issue.

If the behavior is only similar, or you're not sure, please open a new issue so it's easier to track. We'll evaluate if it should be closed as a duplicate of this.

@Uni2K
Copy link

Uni2K commented Jul 11, 2023

If anyone is experiencing this, refer to my #1010 (comment), which suggests using delayHide alongside delayShow to mitigate the issue.

I can reproduce the issue, but only in Firefox & Safari on a Macbook. It seems like not even
delayHide={2} and delayShow={300} will fix is for me. The only thing working is to completely remove delayShow.
Looking forward to a possible fix.

@gabrieljablonski
Copy link
Member

It seems like not even delayHide={2} and delayShow={300} will fix is for me.

@Uni2K what happens when using a slightly higher delayHide value? Please try with something like 50. The idea is there will be enough time for the mouse to reach the new anchor and trigger mouseenter before it closes, so the tooltip will simply reposition, instead of closing and showing again (which gives way to this bug).

@Uni2K
Copy link

Uni2K commented Jul 12, 2023

Okay, so we tested a lot and found out the following things:

delayShow is causing the bug. If it is very large (1000ms) the bug won't appear, only if it is like 300ms. If it is missing, the bug also does not appear.
delayHide can be 0, 50, 100 and even 300, it always occurs.

This code was used to reproduce the issue:

        <div className={"h-full overflow-scroll flex"}>
            <a className={"relative top-[200px] h-[50px]   left-[100px]"}  data-for="tooltip">
                ◕‿‿◕
            </a>
          <a className={"relative top-[220px]  h-[50px]  left-[120px]"}  data-for="tooltip">
            ◕‿‿◕
          </a>
          <a className={"relative top-[600px] h-[50px]  left-[130px]"}   data-for="tooltip">
            ◕‿‿◕
          </a>
        </div>
      <Tooltip
          anchorSelect={"[data-for]"}
          delayHide={50}
          delayShow={300}
          content={"Hello World"}
      >
      </Tooltip>
    </>

See here, this is a video. We are not able to reproduce it in 100%, but maybe 80%. The tooltip is glitching during anchor change. The direction in which it is glitching corresponds to the position of the last opened tooltip.

delayshow.300.mov

See the second time the upper anchor is hovered -> the tooltip glitches from bottom to top. Also we found out that hovering from the bottom direction is causing it the most times.

I hope this helps :s

@gabrieljablonski
Copy link
Member

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.

@gabrieljablonski
Copy link
Member

@Uni2K I've tried many different ways but I'm unable to reproduce this. Are you able to provide a sample project?

@Uni2K
Copy link

Uni2K commented Jul 14, 2023

@gabrieljablonski This glitch was only happening on Safari & Firefox on a Macbook. Never on Chrome, never on windows. I am in vacation and don't have a Macbook here, so I cannot create a sample project which reproduces the bug. The fastest time I could provide you a complete sample project is on 20.07.

At least I can tell you that we just used a standart next.js template. The code above was just used as direct "return" of a page route. We tried a lot before we could find a somewhat reproduceable situation. Even with that, the glitch only happens in about 80% of the time. So, there has to be a random factor that to it.

@danielbarion
Copy link
Member

@Uni2K I do have a Macbook, please create a reproducible example and I'll try to test and debug it from my side, I'll share my findings with @gabrieljablonski and we will try to fix it if possible.

@Uni2K
Copy link

Uni2K commented Jul 16, 2023

Here is the repo: https://codesandbox.io/s/amazing-sanne-lnwmfg

My coworker tested it with his Macbook. He could not reproduce the issue in Firefox, but he could reproduce it in Safari 16.3 on every 5-7 attempt. For now, this is the best I can provide.

@ReactTooltip ReactTooltip deleted a comment from Uni2K Jul 17, 2023
@danielbarion
Copy link
Member

I tried a lot of times but the issue only happened 1 time with me, this will be hard to debug and fix.

I'll take a look if we can reset the Tooltip coordinates when we close it, or something like that.

@gabrieljablonski
Copy link
Member

@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

@Uni2K
Copy link

Uni2K commented Jul 31, 2023

Maybe I can help with a new video, checkout the clicking:

delayshow-bug.mov

@gabrieljablonski gabrieljablonski added the V6 It might get fixed/merged before, but most likely only on V6's release. label Aug 2, 2023
@lopo12123
Copy link

Perhaps it is caused by the same reason.

When their contents are the same, moving from an element that is set not to display tooltip to its neighbor element that displays tooltip, it will appear misaligned.

image
image

When their contents are different, there will be the flickering phenomenon that others have mentioned.
image

@StevenSawtelle
Copy link

I was having this issue (or at least a very similar one, mine was always only flickering in the top left of the page), and this was the hacky solution I came up with to get at least something working using the afterShow/afterHide props to delay the showing until after the flickering was over, in case it helps anyone else:

const [classNameSuffix, setClassNameSuffix] = useState('hidden');
return <Tooltip
          id={uid}
          className={`tooltip ${classNameSuffix}`}
          delayHide={50}
          delayShow={400}
          clickable
          afterShow={() => setTimeout(() => setClassNameSuffix('visible'), 50)}
          afterHide={() => setClassNameSuffix('hidden')}
        >
          {....}
</Tooltip>

and then my scss is just:

.tooltip {
  &.hidden{
    visibility: hidden;
  }

  &.visible{
    visibility: visible;
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Help Wanted V6 It might get fixed/merged before, but most likely only on V6's release.
Projects
None yet
Development

No branches or pull requests

7 participants