Create a Nice, Lightweight JavaScript Tooltip

June 4th, 2008 by Michael Leigeber | 35 Comments | Stumble It! del.icio.us

Editor’s note: This tutorial was written by Michael Leigeber, a web designer and .NET developer who runs the Leigeber Web Development Blog - a blog that’s setting the blogging community buzzing with his beautiful, lightweight JavaScript solutions.

Tooltip - demo

View the JavaScript Tooltip demonstration.

Introduction

To begin, create the 3 files needed for this tutorial (index.html, style.css and script.js) and include the stylesheet and the script from index.html. To make things easy the starter files are available by clicking here.

The most important things to remember when writing JavaScript are to keep the code simple and to script logically. The first thing that needs to be established is precisely what you would like the script to accomplish. Based on the desired functionality it then helps to create a diagram or flow description for any complex script before you get into the code. Doing so can help streamline the logic and keep the script clean.

What we are trying to accomplish…

Create a lightweight script that fades a tooltip with rounded corners in relation to the cursor position.

How does the script need to flow…

  1. Setup the namespace and global variables.
  2. Create a function to display the tooltip that takes two variables, the string to display and an optional width integer.
  3. When the function is called build the tooltip markup if it does not exist and register an onmousemove listener to position the tooltip. Insert the tooltip content into the tooltip and call a function to incrementally fade the tooltip to the target opacity.
  4. On the mouseout event of a “hotspot” reference a function that calls the fade function to incrementally hide the tooltip.

Let’s begin by setting up the JavaScript file. We want to create a namespace to encapsulate the functionality of our script. By doing so, we virtually eliminate the possibility of a conflict with some other script or framework.

var tooltip(){
	return{};
}();

Next, we need to add any variables we want to include on the global level of the namespace. By setting these variables globally we can access them in any of the child functions and quickly change them without sorting through the code.

  • id (string) - id of the tooltip
  • top (integer) – number of pixels to offset the tooltip from the top of the cursor
  • left (integer) – offset to the right of the cursor
  • maxw (integer) – maximum width in pixels of the tooltip
  • speed (integer) – value to increment the tooltip opacity during transition
  • timer (integer) – represents the speed at which the fade function in performed
  • endalpha (integer) – target opacity of the tooltip
  • alpha (integer) – current alpha of the tooltip
  • tt, t, c, b, h – these represent global variables to be set later
  • ie (boolean) – global variable based on browser vendor
 var id = 'tt';
 var top = 3;
 var left = 3;
 var maxw = 300;
 var speed = 10;
 var timer = 20;
 var endalpha = 95;
 var alpha = 0;
 var tt,t,c,b,h;
 var ie = document.all ? true : false;

We need to determine how we want the tooltip to look so we can figure out how to build out the elements to add to the DOM… a rectangle with rounded corners on the top and right corners only. To accomplish this we need a wrapper div and then three nested divs. We can style the divs with the CSS. The markup should look something like this once generated.

<div id="tt">
	<div id="tttop"> </div>
	<div id="ttcont"> </div>
	<div id="ttbot"> </div>
</div>

The first function we will name ‘show’ and it will be accessible by calling tooltip.show(). It will need to take two parameters… the content string and an optional width integer. To begin, it will need to check and see if the tooltip has been added to the DOM yet. If it does not exist the divs need to be built and added to the body. Either way the innerHTML of the contentdiv will need to be set to the content parameter, the height and width set and the fade function set to a timer.

show:function(v,w){
if(tt == null){
 tt  = document.createElement('div');
 tt.setAttribute('id',id);
 t  = document.createElement('div');
 t.setAttribute('id',id  + 'top');
 c  = document.createElement('div');
 c.setAttribute('id',id  + 'cont');
 b  = document.createElement('div');
 b.setAttribute('id',id  + 'bot');
 tt.appendChild(t);
 tt.appendChild(c);
 tt.appendChild(b);
 document.body.appendChild(tt);
 tt.style.opacity  = 0;
 tt.style.filter  = 'alpha(opacity=0)';
 document.onmousemove  = this.pos;
}
tt.style.display  = 'block';
c.innerHTML =  v;
tt.style.width  = w ? w + 'px' : 'auto';

if(!w  && ie){
 t.style.display  = 'none';
 b.style.display  = 'none';
 tt.style.width  = tt.offsetWidth;
 t.style.display  = 'block';
 b.style.display  = 'block';
}

if(tt.offsetWidth  > maxw){tt.style.width = maxw + 'px'}

h =  parseInt(tt.offsetHeight) + top;
clearInterval(tt.timer);
tt.timer =  setInterval(function(){tooltip.fade(1)},timer);
},

The next function we need is the position function that will set the top and left values of the tooltip as the cursor moves. First we calculate the position based on the browser and then we set the values taking into consideration the global offset variables.

pos:function(e){
 var u = ie ? event.clientY + document.documentElement.scrollTop : e.pageY;
 var l = ie ? event.clientX + document.documentElement.scrollLeft : e.pageX;
 tt.style.top = (u - height) + 'px';
 tt.style.left = (l + left) + 'px';
},

Next we need to create a function that will fade the tooltip from its current opacity to the target opacity based on the direction variable that is passed to it.

fade:function(d){
 var a = alpha;
 if((a !=  endalpha && d == 1) || (a != 0 && d == -1)){
   var  i = speed;
   if(endalpha  - a < speed && d == 1){
      i  = endalpha - a;
   } else  if(alpha < speed && d == -1){
      i  = a;
  }
  alpha  = a + (i * d);
  tt.style.opacity  = alpha * .01;
  tt.style.filter  = 'alpha(opacity=' + alpha + ')';
   }else{
     clearInterval(tt.timer);
     if(d  == -1){
     tt.style.display  = 'none';
  }
 }
},

Finally the function to hide the tooltip onmouseout.

hide:function(){
	clearInterval(tt.timer);
	tt.timer = setInterval(function(){tooltip.fade(-1)},timer);
}

That completes the JavaScript. We are left with a 2kb script that is compatible with IE6, IE7, Firefox, Opera and Safari.

Here is the full script

var tooltip=function(){
 var id = 'tt';
 var top = 3;
 var left = 3;
 var maxw = 300;
 var speed = 10;
 var timer = 20;
 var endalpha = 95;
 var alpha = 0;
 var tt,t,c,b,h;
 var ie = document.all ? true : false;
 return{
  show:function(v,w){
   if(tt == null){
    tt = document.createElement('div');
    tt.setAttribute('id',id);
    t = document.createElement('div');
    t.setAttribute('id',id + 'top');
    c = document.createElement('div');
    c.setAttribute('id',id + 'cont');
    b = document.createElement('div');
    b.setAttribute('id',id + 'bot');
    tt.appendChild(t);
    tt.appendChild(c);
    tt.appendChild(b);
    document.body.appendChild(tt);
    tt.style.opacity = 0;
    tt.style.filter = 'alpha(opacity=0)';
    document.onmousemove = this.pos;
   }
   tt.style.display = 'block';
   c.innerHTML = v;
   tt.style.width = w ? w + 'px' : 'auto';
   if(!w && ie){
    t.style.display = 'none';
    b.style.display = 'none';
    tt.style.width = tt.offsetWidth;
    t.style.display = 'block';
    b.style.display = 'block';
   }
  if(tt.offsetWidth > maxw){tt.style.width = maxw + 'px'}
  h = parseInt(tt.offsetHeight) + top;
  clearInterval(tt.timer);
  tt.timer = setInterval(function(){tooltip.fade(1)},timer);
  },
  pos:function(e){
   var u = ie ? event.clientY + document.documentElement.scrollTop : e.pageY;
   var l = ie ? event.clientX + document.documentElement.scrollLeft : e.pageX;
   tt.style.top = (u - h) + 'px';
   tt.style.left = (l + left) + 'px';
  },
  fade:function(d){
   var a = alpha;
   if((a != endalpha && d == 1) || (a != 0 && d == -1)){
    var i = speed;
   if(endalpha - a < speed && d == 1){
    i = endalpha - a;
   }else if(alpha < speed && d == -1){
     i = a;
   }
   alpha = a + (i * d);
   tt.style.opacity = alpha * .01;
   tt.style.filter = 'alpha(opacity=' + alpha + ')';
  }else{
    clearInterval(tt.timer);
     if(d == -1){tt.style.display = 'none'}
  }
 },
 hide:function(){
  clearInterval(tt.timer);
   tt.timer = setInterval(function(){tooltip.fade(-1)},timer);
  }
 };
}();

Now on to the CSS for the tooltip which is completely customizable to match any interface.

#tt {
 position:absolute;
 display:block;
 background:url(images/tt_left.gif) top left no-repeat;
 }
 #tttop {
 display:block;
 height:5px;
 margin-left:5px;
 background:url(images/tt_top.gif) top right no-repeat;
 overflow:hidden;
 }
 #ttcont {
 display:block;
 padding:2px 12px 3px 7px;
 margin-left:5px;
 background:#666;
 color:#fff;
 }
#ttbot {
display:block;
height:5px;
margin-left:5px;
background:url(images/tt_bottom.gif) top right no-repeat;
overflow:hidden;
}

To build and hide a tooltip call the script as below. The second parameter in the show function is optional, if not passed the width will automatically adjust to the content within the maxh limit.

onmouseover="tooltip.show('Testing  123 ', 200);"
onmouseout="tooltip.hide();"

If you run into any issues with this script or have any questions don’t hesitate to contact me at my blog’s contact form.

Downloads

  • starter.zip - starter files to help you follow along the tutorial.
  • tooltip.zip - the completed tooltip script and required files, ready for use.

If you liked this tutorial, make sure to check out the Leigeber Web Development Blog. Stay up-to-date with his stuff by subscribing to his RSS feed.

35 Comments

HMERT

June 4th, 2008

very nice

Matt

June 4th, 2008

This is great. I’d been looking for something similar. Thanks again for great posts.

Sean

June 4th, 2008

Very nice, I do find myself wondering why though? Why “reinvent the wheel” when there’s already several premade libraries that do this for you. Mootools has a really nice, simple tooltip system built in to it already. All in all though… Good Job, keep up the good work.

Jacob Gube

June 4th, 2008

@Sean: That’s an excellent comment, and a valid point - and one which many people are probably thinking of as well.

There are indeed a huge selection of frameworks and libraries available that does tool tips, but the key here is that it’s lightweight.

Let’s take for example, jQuery, which at its compressed state is around 30KB 16KB (for Gzip’ed + minified as of v 1.2.6). Including jQuery and a plugin (or your own script), just for tooltip functionality is quite excessive. If you’re to use jQuery for other things such as handling Ajax requests and events, creating complicated chained effects, and as the backbone of your web application’s end user interface, then the 30KB 16KB is nothing.

Additionally, though this tutorial provides a working, downloadable example of a tooltip script - it’s more a tutorial on JavaScript - to give you inspiration for your own scripts. Some of the concepts covered include working with opacity and alpha, conditionals for different web browsers, and how to write clean and logical code.

Mike

June 4th, 2008

Hi Jacob! This is a great tooltip thank you for making this. I was wondering if it might be possible to add a delay for tooltips coming up?

Ed

June 5th, 2008

Nice tut Jacob. Would it be possible to expand on this in a future post to describe how to make interactive tooltips (a la Netflix)?

Vishal

June 5th, 2008

Really nice script

Diego

June 5th, 2008

thnks nice tut

Jacob Gube

June 5th, 2008

@Mike: Thanks for the compliments, but this wonderful script was contributed by Michael Leigeber of the Leigeber Web Development Blog, so make sure to send him a shout-out.

To answer your question, you can tweak the script’s behavior by playing around with the variables such as speed, timer, alpha, etc. but to achieve your particular change, first look for the hide function, it should look like this:

 hide:function(){
  clearInterval(tt.timer);
   tt.timer = setInterval(function(){tooltip.fade(-1)},timer);
  }

in the last line: modify the timer to an integer… try something like 400, or 500. like this:

 hide:function(){
  clearInterval(tt.timer);
   tt.timer = setInterval(function(){tooltip.fade(-1)},400);
  }

once you’re satisfied, to keep your code clean, declare a variable on top, something like:

var hideDelay = 400;

and then change the value of:

tt.timer = setInterval(function(){tooltip.fade(-1)},timer);

to

tt.timer = setInterval(function(){tooltip.fade(-1)}, hideDelay);

Let me know if you encounter any trouble or need further help - feel free to shoot me an email.

@Ed: That’s a great suggestion! if I see enough requests, I may do a tutorial on a Netflix-style interactive tooltip using jQuery.

Matt

June 5th, 2008

Has anyone else noticed that fox news has started to use this type of ad on their website on certain keywords. That seems so spamish on such a “mainstream” news site. Oh well, the old media is failing.

Real Estate Graphic Design

June 12th, 2008

Love the fade in, beautiful work.

Regis

June 16th, 2008

The visual effect is really great. Thanks.

Devanathan Chandran

June 23rd, 2008

This tooltip effect is really very good.
Thanks

Gustavo Arcila

June 24th, 2008

Great Script, very simple and useful, perfect for people (like me) who hates frameworks (mootols, prototype, etc), resuming … Very good Job, Thank you

choi reyes

July 10th, 2008

hi, i’m just wondering if your tooltip application apply the same functionality if the scroll of the screen enables.
Im trying on my application but it seems the tooltip stays in the upper portion of the screen if I scroll down.
Please Help. Need advice. Thanks.

Jacob Gube

July 10th, 2008

@choi reyes: Got an live example we can check out to better see the issue?

bebjo

July 22nd, 2008

thank you nice application

Stephen

July 27th, 2008

This script is great! Like you said, there isn’t a lightweight choice if you only want a tooltip. The only question I have is how do you make t display underneath the cursor instead of above?

Stijn

July 27th, 2008

Excellent script, does exactly what it’s supposed to do. Nothing more, nothing less.

Martin

July 29th, 2008

Simply, beautiful.

soren

July 30th, 2008

hey Jacob, love the script and the tutorial, very elegant and performs great! I’m just starting to stumble my way into the world of JS and played around with certain variables that I thought might achieve this unseccesfully, but…

how might I got about making it so that after initially opening the tooltip would remain static in that position until the cursor moved off the object? is that possible?

thanks, and either way I love it!

kevin

July 31st, 2008

Very very nice script, thanks for the script…

couple o questions”: how come in IE it causes the windows timer-icon to flicker on and off as if it is loading something constantly as you move your mouse around the page? also is there a way to delay it one second, as in, dont have the tooltip unless some one rests their mouse over the desired text? Thanks!

Rebecca

August 4th, 2008

Looks great! Is there a way to allow users to globally turn on and off the appearance of the tooltips?

Enrico

August 6th, 2008

Very nice, but maybe I found a bug in IE6: if you scroll the page when you are on a tooltip, the box won’t scroll with the page and it’ll stay far away from the cursor. This is not the case in FF.
You can see it here

Sven

August 18th, 2008

very nice work.. but one question..

at the moment i think the “x-y 0 point” is at the bottom left..

what do i have to change to make the top left of the tooltip the 0-point?

greetings

Sven

August 18th, 2008

sorry for asking, got it on my own.. simple mathematics :D

replaced

tt.style.top = (u - h) + ‘px’;
tt.style.left = (l + left) + ‘px’;

by that

tt.style.top = (u + top) + ‘px’;
tt.style.left = (l + left) + ‘px’;

if anyone else is interested.

ehcomunicacion

August 18th, 2008

Very nice effect.

Leave a Comment