Skip to content

[FEAT REQ] Anonymous multiple anchors in v5 #925

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

Closed
Uni2K opened this issue Jan 30, 2023 · 18 comments · Fixed by #928
Closed

[FEAT REQ] Anonymous multiple anchors in v5 #925

Uni2K opened this issue Jan 30, 2023 · 18 comments · Fixed by #928

Comments

@Uni2K
Copy link

Uni2K commented Jan 30, 2023

Related to: #837

Is your feature request related to a problem? Please describe.
In the v4 version, it was easily possible to display a single tooltip on multiple elements using the data-for attribute. Since v5, this was removed and replaced by "anchorIDs". The problem is now that IDs are unique, which is why a single tooltip can be linked to a single DOM element only.

The https://react-tooltip.com/docs/examples/multiple-anchors solutions explained are in my opinion not equivalent.

The Provider solution has the drawbacks, that a) you increase your nesting level, b) you can not dynamically load it, c) you have to manage the anchor state manually, which in your example does not work good (https://react-tooltip.com/docs/examples/state#controlled-tooltip-state).
There is also a lot of documentation missing.

The TooltipWrapper solution (is it related to the provider? It looks like this from the docs but would not make much sense) just unnecessarily bloats the DOM. Just image having 1000 Tooltips in a single page.

Describe the solution you'd like
The v4 solution with data-for was perfect and no other library had a matching function that worked this well. It scales good, cause the number of anchors does not increase the number of tooltips. It was lightweight, cause all it needed was a "data-for" and a "data-tip", something you could generate anywhere. And most important: it did not need you to manage the state across the multiple anchors.

Additional context
My use case is: Large HTML pages are generated in a backend. There are multiple important words that should show a tooltip in the frontend. So, the backend is adding a static data-for and the data-tip with content. There are pages with ~500 important words, so many data-tips. The frontend is receiving the HTML, parsing it and displays it afterwards. The website needs to display large structures, so the overall number of elements is high, which is why more DOM elements or providers will slower the performance noticeably.

@gabrieljablonski
Copy link
Member

gabrieljablonski commented Jan 30, 2023

We appreciate you taking the time to post this.

About the provider solution:

b) you can not dynamically load it

Can you give an example of how this is relevant? I'm not quite sure.

c) you have to manage the anchor state manually, which in your example does not work good (https://react-tooltip.com/docs/examples/state#controlled-tooltip-state)

What do you mean by "having to manage the anchor state manually"? As you can see from the multiple anchors example, there's no explicit code for state management, because it is indeed not required.

The state management example is not great, but it just showcases how you could use it to achieve more complex use-cases. One example from a recent issue is using the tooltip normally, but also closing it when clicking the anchor element.

There is also a lot of documentation missing.

I believe most of the documentation that we could still add is more examples about specific tooltip options, but most of them are quite simple to use. Is there any piece of documentation you would consider very important that is missing?

The TooltipWrapper solution (is it related to the provider? It looks like this from the docs but would not make much sense) just unnecessarily bloats the DOM. Just image having 1000 Tooltips in a single page.

The provider exists solely such that the wrapper can work. As you can see from the first section on the multiple anchors example, you have to setup the provider to use the wrapper.

Yes, it does indeed bloat the DOM, but for us it's obviously not unnecessary since it is the most viable way we found at the time to get the new method to work.

We're planning to try in the future a method similar to how some other libraries do it (such as mui), in which you just have a virtual wrapper element (it does not add an element to the DOM), which only renders the tooltip to the DOM when it is actually showing, and that would also drop the need for a provider.

The v4 solution with data-for was perfect [...] cause the number of anchors does not increase the number of tooltips. [...] And most important: it did not need you to manage the state across the multiple anchors.

Using the provider, you can have as many anchors as you'd like and just one tooltip. As explained already, you don't have to manage the state manually.


The current implementation for v5 is much more in line with modern react than v4, which started having many issues crop up over the time (the original maintainer was not active anymore, and there were over 200 issues open at the time of v5's release) given the implementation was a bit old.

You can do some basic testing with v5, and if it doesn't satisfy what you expect from the library, you could either help us improve it (we would absolutely love that), or stick to v4 while knowing you might run into some bugs.

We really appreciate the time you took to write this, and hopefully you can at least give us some ideas on how to improve the library.

@gabrieljablonski
Copy link
Member

gabrieljablonski commented Jan 30, 2023

I wasn't even actively thinking about this and an idea came to me that might actually solve most of these problems.

#928 might introduce a new prop that will allow you to attach multiple anchors simply using a CSS selector. Feel free to give some ideas over there and be on the lookout for whenever we finish implementing it (assuming it will work fine).

@Uni2K
Copy link
Author

Uni2K commented Jan 30, 2023

Thanks for your answer, here is my feedback on it:

b) you can not dynamically load it

Can you give an example of how this is relevant? I'm not quite sure.

The problem is always bundle size. At the moment, I load the tooltip dynamically once everything was done loading. In this way, I can save a lot of initial JS load. If I need to wrap my entire component tree in a provider I cannot dynamically load it anymore. So my initial JS bundle increases and the page performance suffers. I am using it in production, so like you see, I am very eager that everything is optimized as much as it can be.

What do you mean by "having to manage the anchor state manually"? As you can see from the multiple anchors example, there's no explicit code for state management, because it is indeed not required.

Sorry, this was unclear. With "state" I meant that one has to update the anchorState on mouse events, i.e the hover functionality. From my experience, it is always cumbersome to implement a good working system that triggers something on onMouseEnter and onMouseLeave. There are so many edge cases where the system can fail. Whats with overlap, whats with opacity, and and and. React tooltip did a great job managing all these "hover" states internally. I think it's the wrong way outsourcing this work to the user.

Is there any piece of documentation you would consider very important that is missing?

Yes, I would definitely add some more explanation to https://react-tooltip.com/docs/examples/multiple-anchors. It is unclear why the provider is needed and whats the point of the wrapper. And also that they are connected.

Using the provider, you can have as many anchors as you'd like and just one tooltip. As explained already, you don't have to manage the state manually.

Okay, 1 Tooltip, but for each anchor I need at least 1 Wrapper, right? So, I can't use generic HTML because I would need to wrap each anchor element in a react component, which is not possible.

#928 might introduce a new prop that will allow you to attach multiple anchors simply using a CSS selector. Feel free to give some ideas over there and be on the lookout for whenever we finish implementing it (assuming it will work fine).

Sounds great. Compared to the v4 system, what would the difference be? The tooltip would select the correct anchor element with a css selector?

@gabrieljablonski
Copy link
Member

The problem is always bundle size.

For sure, I definitely wasn't thinking about that, but it's good to know that's an issue.

React tooltip did a great job managing all these "hover" states internally. I think it's the wrong way outsourcing this work to the user.

Maybe this is the documentation not being clear enough again. You can use isOpen and setIsOpen if you want to create some custom logic for handling the tooltip state.

There are so many edge cases where the system can fail. Whats with overlap, whats with opacity, and and and.

We're currently quite happy with the default behavior for the tooltip state (without having to use isOpen/setIsOpen), and our goal is for the default behavior to cover as much of the common use-cases as possible without being too convoluted. When it comes to edge-cases, we are always open for bug reports and improvement suggestions.


Regarding the provider/wrapper, it was implemented to try and mitigate the problem of necessarily using one tooltip for each new anchor element. But in retrospective, although it did help with some use-cases, it turned out to be quite cumbersome to use, and also has other problems such as the ones you've pointed out. Hopefully #928 can completely replace the need for using the provider/wrapper method.

Compared to the v4 system, what would the difference be? The tooltip would select the correct anchor element with a css selector?

It might take a few days for us to implement it, right now it's just an idea (which might not even work). Instead of using anchorId, we'd use a more inclusive CSS selector to find all of the anchor elements.

Usage might look something like:

<>
  <span 
    className="react-tooltip-anchor" 
    data-tooltip-content="I am an anchor element!"
  >
    Anchor 1
  </span>
  <span 
    className="react-tooltip-anchor" 
    data-tooltip-content="So am I!"
  >
    Anchor 2
  </span>
  <span 
    className="react-tooltip-anchor" 
    data-tooltip-content="Don't forget about me!"
  >
    Anchor 3
  </span>
  <Tooltip anchorSelect=".react-tooltip-anchor" />
</>

@Uni2K
Copy link
Author

Uni2K commented Jan 31, 2023

Thanks for the example. If this is going to work, it would be great. Not only would it make the use of multiple anchors very easy, but also make wrapper components and providers unnecessary. I think this is a step in the right direction. :)

@gabrieljablonski
Copy link
Member

gabrieljablonski commented Feb 2, 2023

After some testing, #928 seems very promising to bring back the same functionality we had with v4's data-for attribute.

We'll be doing some more testing and refactoring the documentation to reflect these changes. You're welcome to give some ideas for improvements over there.

@rshelnutt
Copy link

rshelnutt commented Feb 15, 2023

@gabrieljablonski Came to add about our severe regression issues regarding the above, after adopting v5 for a React 18 migration, but appears a resolve is slated for release (hopefully very soon - this is a major hit for us on an incredibly important, public component).

Just wanted to add some thoughts re the TooltipProvider discussion; The documentation does not clearly state that the TooltipProvider is simply a wrapper whose only use is with the TooltipWrapper. Having two separate examples, both repeating the exact same setup markup (component imports, styles, etc), give the appearance that these are two separate entities. Also, probably worth noting in the docs that the TooltipWrapper creates a <span/> around the target - that's liable to break items (especially when used on SVG paths, for things like charts/maps/etc). Docs certainly could use some updates in that regard.

Thank you for your efforts!

@gabrieljablonski
Copy link
Member

@rshelnutt Thanks for letting us know.

We're finishing up work on the PR which will introduce two better ways to use multiple anchor elements (data-tooltip-id and anchorSelect). Since the provider/wrapper method won't do anything more than these new methods, we're deprecating it. The docs will also be updated accordingly.

@rshelnutt
Copy link

@gabrieljablonski Fantastic, thank you for the quick response.

Does your team have a potential timeframe that this might be available?

@gabrieljablonski
Copy link
Member

@rshelnutt We should hopefully have it out by the end of this week. We already finished implementing it over at #928, just missing some final testing before merging.

@rshelnutt
Copy link

We'll plan accordingly - thank you so much for your responsiveness, and for all your efforts getting this resolved.

@gabrieljablonski
Copy link
Member

gabrieljablonski commented Feb 16, 2023

@rshelnutt Since it might be a minute before @danielbarion can have a look at the PR so we can merge it, you're welcome to install the beta version that has just released with yarn add [email protected].

I can say with 95%+ certainty that this will be very close to the official 5.8.0 version. Any changes we end up making are most likely to be very minor bug fixes, and other things that won't affect usage.

For a very simple example on how to use the new features, you can see the beta version readme "Usage" section.

Hopefully, if (and when) you run into more complex use cases, the official 5.8.0 release will already be out alongside the updated docs.

@rshelnutt
Copy link

@gabrieljablonski 🤯 Incredible. Thank you - you and your team are greatly appreciated! Pulling this now 🎉

@rshelnutt
Copy link

rshelnutt commented Feb 16, 2023

@gabrieljablonski Thankfully the beta partially resolved one of our issues, however, it appears there are some problems with it not performing the initial DOM removal of the tooltip following a state change; at which point it appears the connection is severed?

Have a simple, working example here that should provide some context. Tooltip styles are hidden so you can see the break on-screen, can be enabled in the index.js:

https://stackblitz.com/edit/react-n9s2m7?file=src/App.js

@gabrieljablonski
Copy link
Member

@rshelnutt Definitely something weird going on there. I'll be looking into it soon.

@gabrieljablonski
Copy link
Member

v5.8.0 has been released 🚀🚀🚀

@gabrieljablonski Thankfully the beta partially resolved one of our issues, however, it appears there are some problems with it not performing the initial DOM removal of the tooltip following a state change; at which point it appears the connection is severed?

Have a simple, working example here that should provide some context. Tooltip styles are hidden so you can see the break on-screen, can be enabled in the index.js:

https://stackblitz.com/edit/react-n9s2m7?file=src/App.js

This turned out to be simple to fix, just an issue with the anchor element refs becoming stale on unmount.

@Uni2K
Copy link
Author

Uni2K commented Feb 17, 2023

Very nice, thanks for all your effort and commitment. :)

@rshelnutt
Copy link

Thanks again @gabrieljablonski, we're back on-schedule! We'll keep in touch if we happen to run into any funky scenarios. Fantastic work 🏆

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants