Tooltip


5 Jan 2011 Code on Github

Introduction

[May 2, 2018: I've updated this tutorial to fix issues with the viewBox and generally make the code neater.]

The previous tutorial covered basic mouseover effects. This one explains how to use javascript to create a more complex effect: showing a text element when the mouse is hovered over other SVG elements. The code for all the examples on this page can be found here.

The title element

Since writing this tutorial, the title tag has become well supported. However, this tutorial should still be useful if you want a specific style of tooltip. It can also be adapted to create other mouseover effects since it covers several of techniques and principles for making interactive SVG elements. The title tag is also a little annoying to add since you have to create a new element inside the existing one, rather than adding an attribute.

To use the title tag, add it inside the elements like so:

<rect x="40" y="50" width="80" height="100" fill="#007bbf">
    <title>A blue box</title>
</rect>
<rect x="180" y="50" width="80" height="100" fill="#ec008c">
    <title>A pink box</title>
</rect>
blue box A pink box

Then, when you hold your mouse over each element, a tooltip appears after a second or so.

Coding our own

If that's all you want, then the title tag is fine. But what if we wanted to make our own, maybe making the background was a different shape.

The first thing to do is to add a <text> element at the end of your SVG so it will be drawn over the top of the other elements. It doesn't matter what the x and y attributes are, since we will dynamically change them later, and it is current hidden due to the visibility="hidden" attribute. I've given the text element the id "tooltip" which allows us to easily select it.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 200">
    <rect class="tooltip-trigger" x="40" y="50" width="80" height="100" fill="#007bbf" />
    <rect class="tooltip-trigger" x="180" y="50" width="80" height="100" fill="#ec008c" />
    <text id="tooltip" x="10" y="190" visibility="hidden">Tooltip</text>
</svg>

Also add a class to the elements you want to trigger a tooltip. I used "tooltip-trigger" as a class name, but you can use whatever you like, it's just there so we can easily select the elements.

Selecting the tooltip

For this tutorial, I'm going to write the code in a <script> element inside the SVG itself (which means it will still work if I email the SVG to someone). Make sure the script element appears as the last element in the SVG, so the tooltip <text> element exists when the script is run. The code will be the same if you put the JS in a separate file, so long as the SVG is inline, otherwise see my SVG + JS tutorial for how to access the SVG document.

First we need to get the tooltip <text> element. I'm doing this inside an immediately invoked function expression (IIFE). The advantage of this is that it keeps the variables and methods private, so I can have multiple versions running on this page without them interfering with each other (e.g. the tooltip variable won't get overwritten by each script element). It not necessary if you have a single JS file outside of each SVG or have external SVGs embedded into the page, but it's still good practise.

<script type="text/javascript"><![CDATA[
  (function() {
    var tooltip = document.getElementById('tooltip');
  })();
]]></script>

Displaying the tooltip

Next we get the trigger elements with getElementsByClassName and loop through them, adding event handlers for mousemove and mouseout. I've used mousemove rather than mouseover so when we change the position of the tooltip later, it will be constantly updated. If you use mouseover the tooltip to remain stationary after it first appears, which is what happens when you use the <title> element.

var triggers = document.getElementsByClassName('tooltip-trigger');

for (var i = 0; i < triggers.length; i++) {
    triggers[i].addEventListener('mousemove', showTooltip);
    triggers[i].addEventListener('mouseout', hideTooltip);
}

The event handlers added referred to two functions: showTooltip and hideTooltip, which we need to write. These make the tooltip visible or hidden respectively.

function showTooltip(evt) {
  tooltip.setAttributeNS(null, "visibility", "visible");
}

function hideTooltip() {
  tooltip.setAttributeNS(null, "visibility", "hidden");
}

Now if we move the mouse over either box, the tooltip appears at the bottom of the SVG. When we move the mouse off either box, the tooltip disappears.

Tooltip

Positioning the tooltip

Now we want the tooltip to appear next to the mouse. In order for the positioning to work we need to understand the effect of the SVGs viewBox attribute. I've explained in detail how this works here. First we need to get the SVG element which we can do by giving it an id, then using getElementById.

var svg = document.getElementById('tooltip-svg');

Then we update the showTooltip function to get the screen current transform matrix and use this to calculate where the tooltip should be. Again, I explain what getScreenCTM() returns and how to use it here.

function showTooltip(evt) {
	var CTM = svg.getScreenCTM();
	var mouseX = (evt.clientX - CTM.e) / CTM.a;
	var mouseY = (evt.clientY - CTM.f) / CTM.d;
	tooltip.setAttributeNS(null, "x", mouseX + 6 / CTM.a);
	tooltip.setAttributeNS(null, "y", mouseY + 20 / CTM.d);
	tooltip.setAttributeNS(null, "visibility", "visible");
}

I've shifted the position of tooltip by 6 units in the x direction and 20 units in the y direction because I thought that worked well, but you can play around with the numbers. I also added the style dominant-baseline="hanging" to the tooltip text element so the distance is measured from its top. This means there should be a constant distance between the mouse cursor and the tooltip text regardless of the dimensions of the SVG.

Tooltip

Notice that if you move the mouse to the right of the rightmost box, the tooltip is cut off. You can add overflow="visible" to the SVG style to avoid this.

Changing the tooltip text

It's not very useful to display the same text no matter which element is mouseovered. We can change the text by changing firstChild.data for the tooltip element. For example, we can change the mouseover text to display the colour of the square:

Tooltip
tooltip.firstChild.data = evt.target.getAttributeNS(null, "fill");

This method works when you want the mouseover text to display an attribute of elements, but normally this won't be the case. However, we can always add an attribute that contains the text we want to display. Generally when you add attributes contain information we want to use, the attribute should start with data-. For example, I updated the boxes to have data-tooltip-text attributes.

Tooltip
<rect x="40" y="50" width="80" height="100" fill="#007bbf" class="tooltip-trigger" data-tooltip-text="Left box"/>
<rect x="180" y="50" width="80" height="100" fill="#ec008c" class="tooltip-trigger" data-tooltip-text="Right box"/>

Then you can use:

tooltip.firstChild.data = evt.target.getAttributeNS(null, "data-tooltip-text");

Adding the background

Since it can be hard to read mouseover text on dark backgrounds, it makes sense to display the text in its own box. We can make the tooltip more complex by converting it into a <g> element and then adding child elements, such as a <rect> element for a shadow, a <rect> element for a box, and then the tooltip <text> element.

<g id="tooltip" visibility="hidden" >
    <rect x="2" y="2" width="80" height="24" fill="black" opacity="0.4" rx="2" ry="2"/>
    <rect width="80" height="24" fill="white" rx="2" ry="2"/>
    <text x="4" y="6">Tooltip</text>
</g>

The position of the group and the white <rect> element is (0, 0), and the other positions are relative to that. Group elements (<g>) don't have x and y coordinates (or at least they don't change their children's position), so instead we add a translate transform.

var x = (evt.clientX - CTM.e + 6) / CTM.a;
var y = (evt.clientY - CTM.f + 20) / CTM.d;
tooltip.setAttributeNS(null, "transform", "translate(" + x + " " + y + ")");

(Note that I combined adding the (+6, +20) offsets with the calculation of the mouse position, just to make things a bit more efficient).

This way of adding transforms with setAttributeNS is slightly hacky, but it's fine so long are no other transforms are added to the tooltip element (since they will be overwritten). The "correct" method would be to use createSVGTransform() as demonstrated here.

We also need to update the way we change the content of the text element since the tooltip variable no longer directly refers to it. So we can create a new variable to refer to the text inside the first <text> element inside the tooltip group:

var tooltipText = tooltip.getElementsByTagName('text')[0];

Then we change the code that updates the text to use the new variable.

tooltipText.firstChild.data = evt.target.getAttributeNS(null, "data-tooltip-text");

Now our tooltip has a shadow and a box. However, the box and shadow have a fixed width, so we need to make sure it's bigger than the longest text. But then that can look odd with shorter text.

Tooltip

Changing the tooltip length

In order to dynamically change the length of the tooltip boxes we first need to get the boxes, which we can do by getting all the <rect> elements inside the tooltip group.

var tooltipRects = tooltip.getElementsByTagName('rect');

Then, in the showTooltip function we find the length of the tooltip <text> element with getComputedTextLength(), and use this to set the length of the rects.

var length = tooltipText.getComputedTextLength();
for (var i = 0; i < tooltipRects.length; i++) {
    tooltipRects[i].setAttributeNS(null, "width", length + 8);
}

And here's the final SVG with different length boxes. If you want multi-line mouseover text then you could add multiple text elements inside the tooltip group. If you want word-wrapping, then I have some code here that could be used.

The code for all the examples on this page can be found here.

Tooltip

Comments (44)

Paul on 12 Feb 2011, 2:26 a.m.

Thank you, thank you, thank you. Saved me a couple of hours finding all of the info I needed to do this. I wish the Firefox SVG renderer would just show title elements as tooltips. Goodness, how many years has it been?

Peter on 12 Feb 2011, 11:32 p.m.

Thanks, I'm glad you found it helpful.

Tommy on 23 Feb 2011, 4:06 a.m.

Dang! This is slick and was just what I needed for an SVG-based visualization I was working on.

(I'm glad I procrastinated on the project or I would have had to figure it out myself. :)

Viviana on 12 Jul 2011, 5:43 a.m.

Hello Peter,

Thanks for all tutorials, really help me to work with svg. I would like to ask you about svg and android tablets. I know that only works on tablets that have honeycomb, right? is any difference with ipad? Do you know any website where find more information about svg and tablets?

Thanks
Viviana

Peter on 11 Aug 2011, 6:25 p.m.

Hi Viviana, I'm afraid I don't know anything about getting SVG to work on tablets, sorry.

Ville Ojamo on 12 Aug 2011, 7:01 a.m.

Note that if you are working with large SVG, lines 25 and 26 fail when the user scrolls the SVG/page. The tooltips would appear at the wrong place, depending how much the user scrolls even outside the current view.

Easiest way is to just use "evt.pageX" and "evt.pageY" instead of clientX/clientY which take into account the scrolling but these may not be cross-browser compatible. There are sites that explain how to do this correctly.

Ichi on 26 Sep 2011, 6:21 p.m.

Hi,

I'm having the problems that Ville Ojamo says, my tooltip is at the wrong place, I play around changing the values of clientX and clientY but the position is always the same, and far away from the cursor. I've tried changing also client by page, but nothing change.

Could someone help me with this please?

Thanks a lot

Another Great tutorial!! Many thanks

Ichi on 26 Sep 2011, 11:50 p.m.

I sorted it out, I just put negative value on pageX and it worked.

Many thanks for this blog so helpful

Peter on 27 Sep 2011, 12:31 a.m.

Glad you managed to fix your problem Ichi. Ville is right about using pageX and pageY - I've updated the page.

Michal on 25 Nov 2011, 9:24 p.m.

Hi,

I am new in SVG, these tutorials are very helpful.
My problem is that when I am adding viewbox to svg i am loosing the tooltip:(

Mike on 24 Apr 2012, 4:20 p.m.

Your tutorial is just GREAT - Thanks a lot!

Anonymous on 5 Jun 2012, 12:10 p.m.

Hi there is there a way to multipul tooptip boxes that have different colour stokes?

amy on 10 Oct 2012, 6:46 a.m.

i am doing a task regarding SVG map and your tutorial seriously help me a lot.

thank you very much!

but i have a question, how can we change the tooltip information with image?

for example, it is a world map and when user mouse over at a country then a tooltip with the country's map will shown

Peter on 10 Oct 2012, 2:12 p.m.

Hi Amy,

What you'd have to do would be to draw the images off screen, and when the mouse goes over an area, select the right image and move its display in the same way the tooltip background is moved into place.

Anonymous on 17 Oct 2012, 2:24 p.m.

Great! That's exactly what I was looking for.

Thank You!

Manish Khatri on 15 Feb 2013, 7:04 a.m.

Hi,

Its great and I found what I want but can u tell me how dynamic data show on a mouse move

zizou on 7 Mar 2013, 3:47 p.m.

i have a problem ; when i point in my map.svg the viewbox far away from the cursor ;and i don't understand what does 't mean Ichi. please give me a script or any exemple .

mitesh on 29 Jun 2013, 8:41 p.m.

Hi

This guide is excellent but I need the tooltip data from a php scripts

Thank

Deane Saunders-Stowe on 25 Apr 2014, 1:54 p.m.

I've found your tutorials to be really useful - especially now that I'm branching out into animated SVG. I'd never created or modified the shapes of elements using javascript before, and it's proved an invaluable technique for animating gauges and the like. Keep up the good work!

Anonymous on 13 Jun 2014, 9:52 a.m.

I am following your tutorial. Its really helpful for my recent development. But I m having a serious issue and not able to find any solution. Can you please check this question -

https://stackoverflow.com/questions/24187613/external-css-file-doesnt-have-the-effect-on-external-svg-file-in-html-page

How can I do this.

Would be grateful if you kindly reply soon.

Thanks

Greg on 25 Sep 2014, 3:40 a.m.

Hi Peter, A very nice tutorial, thanks for sharing!
I am trying to adapt this to show a tooltip for a marker on a polyline element. I have a graph drawn by using polyline elements to plot the data, and I would like to have a hover text on each marker "dot" to show the value at that point on the graph.
Is this possible?
Cheers,
Greg.

Anonymous on 3 Oct 2014, 11 p.m.

Thanks for the very useful tutorial. I've adopted the code in my project and it works fine. My only problem is that I need to use viewBox attribute, when I added it in the svg tag, it will move the tooltip far away, sometimes invisiable anymore. Take the example of your tooltip_final.svg:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="init(evt)" width="380" height="100" viewBox="0 0 200 100">

When the viewBox attribute is added, it mess up the tooltip. I feel that this has something to do with the coordination system, but I don't know how to fix it. Can you help me?Thanks

Anonymous on 4 Oct 2014, 7:08 p.m.

Very useful, thanks !

Is there a way to show multiple line tooltip?

Thanks

Seyi on 22 Jan 2015, 4:32 p.m.

Your tutorials and examples have been tremendously helpful!

One more thing though...how can I display multiple lines on a tooltip?

Thanks alot for the anticipated response! :)

Andrew C on 7 Mar 2015, 6:48 p.m.

First of all, thanks for all of this information, it has been great and I've been feeling really inspired to make some cool graphics with data that I have.

Is it possible to apply the tooltip functions to classes without having to add the lines of code for each one? Similar to the way you suggested for the '.some-class-name:hover' method in the <style> element?

Many thanks again for sharing,

Andrew

Mark on 23 Jul 2015, 1:07 p.m.

Hi everybody,

For some reason, Dreamweaver CC is indicating that I have an coding error on the line that reads <![CDATA[. the first line of code after the the <script> tag. I copied and pasted the code directly from the tutorial, so I have no idea what or where the problem could be. While I can view the svg image and tooltips in Dreamweaver "Live View" mode, neither the map or tooltips appear in the web browser when uploaded onto my server - the screen is just blank. Any ideas as to what could be wrong?

Thanks for any help you can provide.

Kind regards,

Mark

Anonymous on 30 Sep 2015, 8:24 a.m.

HORRIBLE tutorial. There needs to be a full code somewhere. I had no idea where to put cdata and kept getting errors.

No.

Samina on 29 Oct 2015, 10:09 a.m.

Hi Peter,

this is really helpful and step by step learning for a beginners in SVG's. very good topic , very god effort. Thank you so much again.

Best Regards,

Samina on 29 Oct 2015, 10:12 a.m.

Hi Peter,

this is realy good effort to help beginners with SVG issues.

Best Regards,

Anonymous on 19 Jan 2016, 9:19 a.m.

Very nice Tutorial! Thank you very much!

I have just one little issue... How can I create a linebreak in the Tooltip-Text? (would like to use something like '\n' - but that doesn't work...

Has anyone a hint ?

Thanks

DB on 19 Jan 2016, 10:27 a.m.

Thanks, very useful!!!

AnonymousJ on 16 Mar 2016, 11:30 a.m.

Hi Peter,

Great Writing!

Thanks a lot!

Glaucia on 26 Apr 2016, 2:42 a.m.

Hi Peter, thank you for your tutorial. It's very useful. However, I really need to have multiple lines in my tooltip, but I can't get this working. Do you have any tips?

Thank you very much!

Laura on 25 May 2016, 1:52 a.m.

I realize this post is a bunch of years old by now. But I'm trying to implement it and having some issues. Perhaps syntax should be different now? In any case, I'm trying to add a tooltip to a path. It sort of works. I can see that there's a tooltip around, but it sits a long ways away from the element itself. How can I make sure the tooltip stays near the mouse itself?

Anonymous on 20 Sep 2016, 11:32 p.m.

Hello Peter,

Is it possible to have html tooltip for SVG?

Thanks

Andrei Carligeanu on 5 Nov 2016, 9:07 a.m.

Hi. How to fix the tootltip position? My svg map is responsive but when i look on my tablet the position of the toolbar is changed.

Daniel Kruijmel on 13 Feb 2017, 2:47 p.m.

Hi Peter,

I've been trying to add images to the tooltips, but failed again and again.

If it is in fact possible to do so, I was hoping if you could lend your expertise on the matter.

Thanks in advance.

Daniel

davea0511 on 8 Sep 2017, 11:09 p.m.

I know this is a necropost, but this is still the only way to create an SVG tooltip that you can actually format. Thanks for keeping it online!

Mikbr on 13 Sep 2017, 10:54 p.m.

Hi there,

I have been searching and searching and I cannot find out how to include a new line/break within the tooltip. Do you know how I possibly could do that?

And thank you for the tutorial, very useful!

Duane on 17 Sep 2018, 9:19 p.m.

Thanks Peter! Your tutorials have made my task easier.

Guido on 28 Sep 2019, 3:54 p.m.

excellent work Peter, almost 9 years later, still helps a lot.

little error in the code, should be corrected.

triggers[i].addEventListener('mousemove', ShowTooltip);
triggers[i].addEventListener('mouseout', HideTooltip);

Peter on 29 Sep 2019, 2:56 p.m.

Thanks, I've update the text.

Guy Forssman on 8 Dec 2019, 3:33 p.m.

Hi Peter,

Thanks for these tutorials they help me a lot. As I want to display a real tree with almost 100 leafs on a joomla site I want to refrain as much as possible from external libraries like javascript and jquery.
I can't seem to get text ( 2 to 3 lines) belonging to leaf1 displayed as I hover over leaf1, leaf2 should display another text on hovered over. Ideally this text would come over the trunk.
I have the hovering and clicking working but the text eludes me for some reason (https://codepen.io/Forssux/pen/vYENyMX?editors=1111) thanks for reading anyway and your posts.

Brian on 2 Jun 2020, 9:22 p.m.

This is exactly what I was looking for, solid work!