Creating Custom Tooltips with jQuery UI
TJ VanToll | March 6, 2013
Tooltips are a common user interface element used to provide context for controls. A tooltip is shown most frequently when a user hovers over an element with the mouse pointer. Tooltips were introduced to the Web way back in HTML 3 with the title attribute. When an element has a title attribute, all desktop browsers natively provide a tooltip.
But while native tooltips are perfect for quick textual tips, their behavior and appearance can’t be customized, and this means that they don’t scale well to the complex requirements of modern Web applications. The 1.9 release of jQuery UI includes a new tooltip widget that’s intended to be an accessible, customizable and themeable replacement for the native tooltips provided by the browser.
Unlike native tooltips, jQuery UI’s tooltips look consistent across browsers and operating systems. Another key difference is that jQuery UI's tooltips are displayed when a control receives focus as well as on hover, which helps provide context for keyboard users as well as for users on touch-enabled devices.
In this article, I explain what the tooltip widget is and how you can use it to create highly customized tooltips for your Web application. Let's get started.
Creating Basic Tooltips
Because the tooltip widget was designed to be a replacement for native tooltips, it recognizes the same markup pattern the browser uses to create native tooltips—the title attribute. Take the following text input:
<input type=”text” id=”input” title=”I am a tooltip!”>
All browsers will natively show the user a tooltip when the user hovers over this text input. Figure 1 shows the display in a few modern browsers.
Figure 1. Native Tooltips in (left to right) Internet Explorer 10, Firefox 16 and Chrome 22, All on Windows 8
To replace the native tooltip experience with a jQuery UI tooltip, simply select the appropriate element and call the tooltip method. The text of the JQuery UI tooltip will still be the title attribute of the HTML element. The following example applies the tooltip widget to the text input:
$(function() {
$( '#input' ).tooltip();
});
Figure 2 shows what the user will see when the mouse pointer hovers over the text input now.
Figure 2. Default jQuery UI Tooltip Display
Fully Replacing Native Tooltips
While you can call the tooltip method on individual elements, you can also call it on a container element. Doing this adds a tooltip for any descendant elements with a title attribute. For example, the following adds tooltips to both text inputs:
<div id="container">
<input type="text" title="One">
<input type="text" title="Two">
</div>
<script>
$(function() {
$( '#container' ).tooltip();
});
</script>
To build on this, if you want to switch all native tooltips to jQuery UI tooltips, call the tooltip method after selecting the document itself:
$(function() {
$( document ).tooltip();
});
When the tooltip method is called on a container element, internally the tooltip widget makes use of event delegation to handle displaying the tooltips. This means that new elements added to the DOM with a title attribute will automatically receive a jQuery UI tooltip.
If you need more fine-grained control over which elements will show tooltips, you can use the items option. When provided, this option will show JQuery tooltips only for elements that match the given selector. Take the following example:
<input type="text" title="input" />
<a href="#" title="anchor">anchor</a>
<script>
$(function() {
$( document ).tooltip({
items: 'a'
});
});
</script>
In this example, the anchor will show a jQuery UI tooltip on hover because it matches the "a" selector passed to the items option. Since the text input does not match the selector, it will fall back to showing a native tooltip on hover.
Customization
Now that you've seen how to create tooltips, let's look at how they can be customized. Unlike native tooltips, the tooltip widget provides a variety of hooks for full customization of visual display, behavior and functionality. The following sections describe some of the more common things you might need to do.
Styling Tooltips
Native tooltips are not part of the DOM; therefore, you cannot change their display with CSS. Since jQuery UI's tooltips are in the DOM, you can use any CSS you want to customize their display.
All tooltips have the class ui-tooltip that you can use to apply custom styling. For example, if you need blue tooltips for your application, you could use the following:
.ui-tooltip {
background: blue;
color: white;
}
If you don’t want to handle the design yourself, jQuery UI comes with more than 20 predefined themes that can be used as a starting point. Figure 3 shows the default look of the tooltip in a few of the predefined themes.
Figure 3. Display of jQuery UI Tooltips with Built-in Themes: (from left to right) humanity, le-frog, redmond, and ui-darkness
Additionally, the jQuery UI project has a full application, ThemeRoller, that you can use to customize the look of all jQuery UI widgets in your project. You can start from one of the predefined themes or create your own theme from scratch. Check it out here.
Styling a Specific Tooltip
After your tooltip styling is set, you'll probably run into at least one tooltip that you want to be different from the rest. For this, the widget provides the tooltipClass option. Take the following example:
<input type=”text” id=”input” title=”I am a tooltip!”>
<script>
$( '#input' ).tooltip({
tooltipClass: 'blueTooltip'
});
</script>
This code will add a class named "blueTooltip" to the tooltip created on the text box. Any other tooltips on the page will not be affected.
Showing and Hiding
Native tooltips are displayed roughly one second after a user hovers over an element, and they hide shortly after the user leaves. The tooltip widget enables you to customize the timing of the display, as well as to use custom animations when showing and hiding tooltips.
The show and hide options can take a variety of values, but in their simplest form they take the number of milliseconds to wait before showing or hiding a tooltip. In the following example, all tooltips will be shown and hidden after 500 milliseconds:
$( document ).tooltip({
show: 500,
hide: 500
});
By passing in a string, you can use one of jQuery UI's effects to add a custom animation when the tooltip is shown or hidden. The following example uses the bounce effect to show tooltips and the explode effect to hide them:
$( document ).tooltip({
show: 'bounce',
hide: 'explode'
});
A full list of the effects jQuery UI supports can be found here.
If you don't want to use any animations, turn them off by passing in false for the options. The following example will show and hide the tooltips immediately:
$( document ).tooltip({
show: false,
hide: false
});
Finally, the show and hide options also accept an object with duration, effect and easing properties. The duration is the number of milliseconds to wait before showing or hiding, the effect is a jQuery UI named effect (like the bounce effect mentioned earlier), and the easing determines the speed at which the animation progresses. A full list of the easings that jQuery UI supports can be found here.
As an example, the following code hides all tooltips after two seconds using the puff effect and a swing easing.
$( document ).tooltip({
hide: {
duration: 2000,
effect: 'puff',
easing: 'swing'
}
});
As with any option in the tooltip widget, the show and hide options aren’t required. If values aren’t specified, a fadeIn animation with linear easing and a 400 millisecond duration is used.
Programmatic Control
While the show and hide options control how a tooltip is shown, they offer no control over when it is. For that, the tooltip widget provides open and close methods. Take a look at this example:
<input type="text" id="tooltip" title="I am a tooltip!">
<button id="open">Open</button>
<button id="close">Close</button>
<script>
$(function() {
$( '#tooltip' ).tooltip();
$( '#open' ).on( 'click', function() {
$( '#tooltip' ).tooltip( 'open' );
});
$( '#close' ).on( 'click', function() {
$( '#tooltip' ).tooltip( 'close' );
});
});
</script>
Here, click event handlers are attached to the Open and Close buttons to show and hide the tooltip on the input. If you are unfamiliar with jQuery UI, the line $( '#tooltip' ).tooltip( 'open' ) might look a little strange at first; it is actually invoking the open method of the tooltip widget. The pattern of passing a string to the widget to invoke a method is common to all widgets in jQuery UI.
One important fact to note is that the open and close methods can be called only on nondelegated tooltips. These methods won’t work for tooltips of HTML elements that inherit tooltip behavior from their parent elements. Here’s an example:
<input type="text" id="input1" title="I am a tooltip!">
<div id="container">
<input type="text" id="input2" title="I am a tooltip!">
</div>
<script>
$(function() {
$( '#input1' ).tooltip();
// Calling the open method will work as expected.
$( '#input1' ).tooltip( 'open' );
// Set up event delegated tooltips for any children of the container div,
// including the 2nd input.
$( '#container' ).tooltip();
// Since a tooltip is only created on the 2nd input via event delegation,
// calling the open method will throw an error.
// $( '#input2' ).tooltip( 'open' );
// You can, however, instantiate a tooltip directly on the 2nd input and then
// call the open method.
$( '#input2' ).tooltip().tooltip( 'open' );
});
</script>
To demonstrate a situation where the open and close methods might be useful, consider the following sign-up form:
<form id="signup">
<fieldset>
<legend>Sign Up Now</legend>
<label for="username">Username:</label>
<input type="text" name="username" id="username"
title="User name must be between 8 and 32 characters.">
<label for="password">Password:</label>
<input type="password" name="password"
title="Password must contain at least one number.">
<label for="password2">Confirm Password:</label>
<input type="password" name="password2"
title="Please re-type your password for confirmation.">
</fieldset>
</form>
<button id="open">Open Help</button>
<button id="close">Close Help</button>
<script>
$(function() {
var $tooltips = $( '#signup [title]' ).tooltip();
$( '#open' ).on( 'click', function() {
$tooltips.tooltip( 'open' );
});
$( '#close' ).on( 'click', function() {
$tooltips.tooltip( 'close' );
});
});
</script>
In the example, Open Help and Close Help buttons are provided with the sign-up form to allow users to show and hide all available help at once.
Using Customized Content
One of the more limiting aspects of native tooltips is that they can contain only plain text. Even simple formatting like bold or italics isn’t allowed. Through the content option, the tooltip widget allows for full HTML content within a tooltip. For example, the following code produces the tooltip shown in Figure 4.
<input type=”text” id=”input”>
<script>
$( document ).tooltip({
content: 'I am a <b>tooltip</b>!',
items: 'input'
});
</script>
Figure 4. Tooltip with Custom HTML
You can see in Figure 4 that the content option is indeed interpreted as HTML rather than plain text. Also, note that the example input has no title attribute. Internally, when a tooltip is created, the widget first checks whether the content option is provided. If it is, the widget uses it. If the content option isn’t present, the widget prefills the content option with the value of the element's title attribute. Therefore, when the content option is used, a title attribute is not necessary.
Dynamic and Server-Side Loaded Content
In addition to accepting HTML, the widget's content option also accepts a function that can be invoked with the content to be used. How might this be useful? It allows you to perform logic to determine the content of the tooltip before it is displayed. For example:
$( document ).tooltip({
content: function( callback ) {
if ( $(this).is('input') ) {
callback( 'foo' );
} else {
callback( 'bar' );
}
}
});
In this code, all input elements with a title attribute will have a "foo" tooltip, and all others will have a "bar" tooltip.
An even more powerful use of the parameter is to use it to load content via AJAX, as shown here:
$( document ).tooltip({
content: function( callback ) {
$.ajax({
url: 'https://foo.com',
success: function( data ) {
callback( data );
}
});
}
});
In this code, as soon as the user performs an action that shows a tooltip, an AJAX request is sent to the server. When the request returns, the response body will be set as the content of the tooltip. The tooltip will then be displayed automatically.
It's important to note that the tooltip will not be displayed until the function passed to the content option ("callback" in the preceding example) is called. Therefore, when you’re loading content via AJAX, the tooltip will not display until the request completes.
Because of this potential delay, dynamically retrieving the content of a tooltip is best when the content cannot be determined on page load. For example, consider a user name field that validates on the server to ensure that the user name provided is available. Because this check relies on user input, it is an excellent use for a tooltip with dynamically loaded content.
Positioning Tooltips
Yet another limitation of native tooltips is that they give you no control over where the browser will place the tooltip. By default, jQuery UI's tooltip widget will place tooltips on the bottom right of selected elements to mimic the most common placement used by modern browsers. However, with the position option, the tooltip widget will leverage jQuery UI's position utility to allow you to place tooltips wherever you want them.
The position option takes an object with four optional properties: my, at, of, and collision. To show how they work, let's look at some examples. Here’s the first:
<input type="text" id="tooltip" title="I am a tooltip!">
<script>
$( '#tooltip' ).tooltip({
position: {
my: 'left center',
at: 'right center'
}
});
</script>
The my property controls the positioning of the tooltip itself. Following CSS conventions, the first value is the horizontal alignment and the second value is the vertical alignment. Therefore, the value of the my property is pointing at the "horizontal left, vertical center" of the tooltip. You can see this point in Figure 5.
Figure 5. The Point the My Property Points At
The of property determines the element the tooltip will be positioned relative to. It defaults to the selected element; in the preceding example, this is the selected text input. You are unlikely to need to change this because it is unusual to display tooltips on alternate elements.
The at property controls where the tooltip will be placed. In the example, the value "right center" means that the tooltip will be placed at the "horizontal right, vertical center" of the text box. You can see this point in Figure 6.
Figure 6. The Point the At Property Points To
To put this all together, the horizontal left, vertical center of the tooltip is placed at the horizontal right, vertical center of the text box. Figure 7 shows the result.
Figure 7. The Positioned Tooltip
It is quite common to want a gap between the tooltip and its associated element. To handle this, each dimension in the my and at properties can contain pixel or percentage-based offsets. Here's an example, and you can see the results in Figure 8.
<input type="text" id="tooltip" title="I am a tooltip!">
<script>
$( '#tooltip' ).tooltip({
position: {
my: 'left center',
at: 'right+10 center'
}
});
</script>
Figure 8. Using Offsets to Alter the Tooltip's Position
Because "right+10" is specified for the value of the at property, the tooltip is now positioned 10 pixels to the right of the input. Percentage-based values such as "right+10%", and "right-10%" are also acceptable. Other CSS units, such as ems and rems, are not supported.
Collision Detection
The fourth property of the position option—collision—determines what happens when a displayed tooltip does not fit within the window. The possible values are "flipfit", "flip", "fit", and "none". To see what they do, look at Figure 9.
Figure 9. Effects for the Collision Property
Here, each of the text inputs specify the collision property that their corresponding tooltips are using. The "none" textbox in Figure 9 shows what happens when no collision detection is specified: roughly half the tooltip is off the screen and not viewable by the user.
The flip behavior will attempt to flip the tooltip to position it fully on the screen. Note that the flip input's tooltip is aligned with the right side of the input rather than the left. The fit behavior will attempt to shift the tooltip to position it on the screen. The fit input's tooltip is aligned with the right edge of the window itself.
The default behavior, flipfit, will first run the flip behavior. If the flip behavior cannot position the tooltip on the screen, the fit behavior is performed. In Figure 9, the flipfit tooltip is identical to the flip example because the flip behavior placed the tooltip on the screen (therefore, the fit behavior didn’t need to run).
The best way to learn about the collision option, or any of the options of the position utility, is to play with them in a live example. jQuery UI's docs have a playground where you can experiment with the different values. Furthermore, there is thorough documentation on the supported values and how to use them here.
Wrapping Up
Tooltips are a valuable tool in a Web developer's toolbox. Browsers offer tooltips natively through the use of the title attribute, but the fact that native tooltips cannot be customized limits their usefulness in modern, complex Web applications. Because of its ease of use and ease of customization, jQuery UI's tooltip widget provides an excellent replacement for the native functionality.
To get started, you can download a custom jQuery UI build. The widget provides more options, methods and events than I was able to cover in this article. Full documentation is available on the jQuery UI site.
This article is part of the HTML5 tech series from the Internet Explorer team. Try-out the concepts in this article with 3 months of free BrowserStack cross-browser testing @https://modern.IE
About the Author
TJ VanToll is a Web developer and jQuery UI team member. He lives in Lansing, Michigan, and writes about his experiences with jQuery, HTML 5, CSS and other things that strike his fancy on his blog. He is the proud father of twin sons, and when he’s not on the Internet, he’s usually found chasing them in circles. Find TJ on his Blog and on Twitter-@tjvantoll.