EDIT: Ok, after publishing I realized that "nothing else" is an exaggeration. There is quite a bit of CSS too. But no other JS dependency 🙈
Tooltips are a fantastic way of adding context to a piece of UI.
Recently I had to use lots of them at work. And I'm a rather lazy person, so to make it easier I created a <Tooltip />
component that I could use to add tooltips to pretty much anything.
It is a no-sweat component, with no dependency other than React itself.
Be aware that most of the patterns applied here are not exclusive to React so you may learn a few new things even React is not your cup of tea. 🙂
Here's a demo before we move into the details:
How to make it
What makes this component so good is that it leverages good old CSS sorcery with the flexibility of React children
prop. We only need two files to make it work: Tooltip.css
and Tooltip.js
.
Let's talk about the CSS of it first.
Tooltip.css
There's a handful of techniques at play here:
- Custom properties (CSS vars) that control color, spacing and arrow size
- CSS border triangles and
before
pseudo-elements to make the arrows - Some smart absolute positioning and wrapping to put everything in the right place
Have a look at the Tooltip.css
file.
You can see that half of it is styling to make the tooltip appear in different directions. A CSS preprocessor could make this code leaner but remember, we are keeping it simple.
The biggest takeaway of Tooltip.css
is understanding that by wrapping a React component with <Tooltip>
we are also wrapping it with an element styled by the Tooltip-Wrapper
class.
That CSS class anchors the positioning of the tooltips with position: relative
. That way we can use position: absolute
in each tooltip with its top
, right
, bottom
, and left
values relative to the element we are wrapping.
Now that we understand that Tooltip.css
handles how the tooltip looks and where it goes, let's talk about its .js
counterpart.
Tooltip.js
Tooltip.js
does four important things:
- It takes everything inside a
<Tooltip>
component and moves it inside adiv
withTooltip-Wrapper
class by usingprops.children
- It controls what content will be inside the tooltip bubble with
props.content
- It controls where the bubble will appear using the value passed to
props.direction
as a class. - It controls when it shows by listening to
onMouseEnter
andonMouseLeave
events
Here, have a snoop at Tooltip.js
:
Can you see how it works together with Tooltip.css
?
The biggest takeaway of this file is that it has the minimal necessary logic to make CSS shine. All the work it does is moving the props you passed to <Tooltip>
into the right places.
So at the end of the day (or at the end of the reconciliation 😄), all that Tooltip.js does is transforming this:
<Tooltip content="Hello, I'm a tooltip" direction="right">
<button>I'm a button</button>
</Tooltip>
Into this:
<div
className="Tooltip-Wrapper"
onMouseEnter={showTip}
onMouseLeave={hideTip}
>
<button>I'm a button</button>
{active && (
<div className={`Tooltip-Tip right`}>
Hello, I'm a tooltip
</div>
)}
</div>
How to use it
After learning how it works, the "how to use it" should be pretty simple to grasp.
All you need to do is import the Tooltip
component and use it as a wrapper. Make it go above anything you want to show a tooltip on hover.
It takes three props:
-
content
, which will be what's inside the tooltip- Required, It can be anything JSX, text, images, other components, it's up to you
-
direction
, which controls where the tooltip will show- Optional, accepts
top
,right
,bottom
, andleft
. Defaults totop
- Optional, accepts
-
delay
, how much time, in milliseconds, it takes for the tooltip to show.- Optional, defaults to 400ms
Add a simple wrap with a some of these props and bam now every hover on anything that is inside <Tooltip>
will show a small balloon of content.
Here's how I did it in the demo:
Pretty cool, right?
What I love the most about modern web development is how components make stuff easier to implement after some initial setup.
Doing the same thing during jQuery times would take a lot of repetition, duplication, and much more elbow grease.
And as a final reflection, I'm sure that some things in front-end look crazy complex now but these kinds of techniques make me feel that we are moving in the right direction.
And that's it, thanks for reading. I hope this article is useful on your front-end journey!
As always, comments and feedback are super welcome, so what would you change or improve in this implementation?
Cover photo by Drew Beamer on Unsplash
Hey, let's connect 👋
Follow me on Twitter and let me know you liked this article!
And if you really liked it, make sure to share it with your friends, that'll help me a lot 😄
Top comments (11)
I love when someone breaks something down you might see from a React component library like Material UI into their own reusable React components. I appreciate the time and effort you took to recreate something that most of us might take for granted. Great work!!
Hey, James. Thank you! I think that there is a lot to learn from doing so and it makes me super happy to know that I'm not the only one learning with it 😄
Absolutely! There is always value in "looking under the hood" and recreating how something works. It reminds me of a recent DEV post that recreated common built-in JavaScript functions like map. You got me thinking about what component I could try to recreate. I sort of did that with my side navigation bar in my newest portfolio site, but it's not exactly as reusable as your tooltip!
Your head is the right place but I'd say my solution scratches a different itch.
title
attr is great until you need to style or add custom behavior to your tooltips. If it was the absolute solution 100% of the time we wouldn't have decade-old tooltip libraries. 🙂Nice job!
A few thoughts:
Hey, Giorgio. Thanks! You have excellent points.
Agreed. IMO, tooltips are usually an
onHover
component but I can see value on toggling it on and offonClick
.Love the idea of direction "auto". Maybe it doesn't even need to be a specific direction but a prop like
autoAdjust
or something like that. I think Intersection Observer API would be the right tool for it, or maybe something simpler with media-queries.I haven't thought of that, nice call. I'm not sure if it is a CSS only thing though, as the event that triggers the tooltip hide is the wrapper
onMouseLeave
🤔. If I had to implement only one of the suggestions I'd pick this one for sure.Parabéns pelo tutorial Vitor!
O Tooltip ficou enxuto e muito funcional.
Me ajudou aqui na aplicação de um trabalho.
Como estou utilizando styled, fiz pequenas adaptações.
gist.github.com/theandersonn/9964e...
What does the fox say!!
you may want to use
display: contents
on the.Tooltip-Wrapper
classI'm really liking your extremely reusable components series. Each article is extremely helpful!
Hey, z2lai! Thanks for the feedback, it warms my heart to know that they are being helpful. 😄