Sometimes in frontend development there are really simple UI elements that we take for granted. I’d argue that tooltips fall squarely in that category. They get taken for granted because they just work, and generally if something works you shouldn’t mess with it, right?
Well at Swrve we felt that tooltips weren’t quite as good as they could be , at least in React/Redux apps, and here’s why:
1. Orphaned tooltips
Ever remove an element from the DOM and have a tooltip linger around? React apps may redraw your DOM, replacing a button that has a tooltip with a different button instance on click. I found that under the hood projects like React-Tooltip and others often referred to DOM refs or, heaven forbid, jQuery.
The fact is, a React app should wherever possible use the virtual DOM and synthetic events rather than relying on actually rendered DOM nodes or a library that reads the DOM.
It turns out that handling all the important events for a tooltip implementation are available to us for free with synthetic events and lifecycle hooks so you can ensure that a tooltip is removed before its parent unmounts.
2. React is composed, tooltips should be too
I mentioned above that a tooltip should unmount when its parent does, but that’s not quite how tooltips work in HotTip. With React we build UIs by composition, so that’s the interface that HotTip uses. In JSX this would mean that the tooltip is the parent and the element that the tooltip belongs to is actually the tooltip’s child.
You may be familiar with the decorator pattern, es6 or otherwise, and that’s all this is. You decorate your element with tooltip behaviour, your element doesn’t change but your tooltips are managed, easy!
HotTip doesn’t have endlessly customisable tooltips, they’re pretty simple. It also doesn’t do realtime repositioning the way jQuery solutions might. What it does do is calculate whether there is enough room to display your tooltip centred or if you need to offset to make use of the available space, then these are applied as CSS classes.
This is a lightweight and powerful solution that is possible because of the constraints HotTip ships with (max-width etc.). You save on performance by not needing to calculate based on mouse position and you get a consistent result between development and production.
Redux manages your app state. Is a tooltip state? Of course it is. Should you ever need more than one tooltip at a time? I don’t think so.
Given these two factors a singleton hotTip redux store seems like a sensible solution to use and it is very efficient.
- No jQuery or browser node references, do it the React way
- Add tooltips by writing normal JSX tags wrapping your elements.
- Positioning is relative to an element, not the cursor. There are no expensive recalculations on mouse move events this way and the result is consistent.
- CSS classes determine most of the layout
- All your state is in Redux, there is no component state.
- Events kick off from the virtual DOM and in all likelihood complete before the render cycle completes so you’ll get efficient rendering.
HotTip is open sourced, and the source is reasonably straightforward, (read it here). If there’s anything you’d like to see added, changed, or if you want to fork of this as a starting point, we’d love to hear from you and see what direction you went with it. HotTip is maintained by Swrve engineers but we’d love to collaborate on it.