Data-driven tooltips (popovers) in re-frame

Damian Hryniewicz
magnet.coop
Published in
2 min readMay 3, 2019

Most of our projects have a need to display tooltips. Those tooltips can vary in purpose. They can be as simple as some text that appears on hover. But sometimes it has to be an interactive element. Think of a contextual menu that appears on right mouse click. How do you close that tooltip?

First there is most obvious way — if you opened it with a button then close it with a button.

Sure, it’s dead simple. But it’s completely uncontrollable from outside this element.

I’m no UX expert but I’m pretty sure that user expects that the tooltip will hide also when he/she clicks anywhere else.

In previous projects we were implementing this behaviour by leveraging React’s lifecycle methods. A tooltip, when spawned, used component-did-mount to create a listener on document to listen for clicks. If that click happened outside of that tooltip controller, the tooltip was destroyed. But there’s still that listener hanging. component-will-unmount in the tooltip was destroying that listener.

The approach above worked, but required using lifecycle methods. Reagent community advises not to do it.

That’s where re-frame kicks in!

Markup of the elements that use tooltips will remain very much the same. The difference is that now the information whether a tooltip should be displayed or not will be stored in re-frame’s appdb. This is an example appdb state:

{… …
:tooltips-controls {"id111" {:id "id111"
:destroy-on-click-out? true}
"id222" {:id "id222"
:destroy-on-click-out? false}}
… …}

As you can see above, it’s a map of maps. Each individual map represents one tooltip. In the markup you should have a tooltip that subscribes to its respective tooltip control data. If it is there, then it means that that tooltip should be spawned.

And here it is! And look how easy it is to make it more configurable. In line 58 of tooltip.cljs you can see that I’m filtering only the tooltips that have :destroy-on-click-out? set to true. That’s all it took to make a popover resist being deleted when user clicks outside that controller.

--

--

Damian Hryniewicz
magnet.coop

There's a ton of tutorials on how to become functional developer. If one day people will decide to go back to OOP I'm screwed - I'm a native FP developer.