Using PageNote Tooltips

© 2013 Jim Williams, version of 8/8/2013
placement: below 3 target-block

PageNote tooltips are a powerful, highly intuitive generalization of the traditional tooltip concept. When the mouse stops over a tooltip target, a target annotation is embedded in a tooltip skin and displayed according to a placement specification. The skin together with the placement specification constitute the tooltip's template. And the resulting displayed tooltip is a page note. No user-supplied JavaScript is involved.

The pagenotes.js script implements PageNote tooltips. It is designed to run on modern standards based browsers, including recent versions of Firefox, Internet Explorer, and Chrome. To use the script, simply include it in a document's <head> element. The script is offered under the MIT license.

Page notes have a large variety of uses. They can create balloon tooltips over a picture. They can be used for an unusually precise approach to interlinear bible translatons.

Also available as pagenotes-min.js (13 KB)


In the following example, point your mouse at the word "cool". A page note will appear after a very short delay. The purpose of the delay is to ensure that the mouse has stopped, in order to avoid spurious displays when the mouse merely travels across the word "cool". We mark the page note's annotation with a new anno attribute rather than the traditional title attribute in order to avoid an unfortunate race condition. [details]

Page notes are cool.

[target] [formatting]

   .red-target { color:#AA0030; cursor:default }
   .red-target:hover { 
       color:#C90030; position:relative; left:1px; top:1px }  
  Page notes are 
     <span class="red-target" anno="<i>really</i> cool">cool</span>

We refer to the mouse stopping over a tooltip target as a mousepoint event. This can be implemented as a real JavaScript event, as shown in the paper The Mousepoint Event. The race condition arises because the pagenote.js script suspends briefly in order to detect the stopping of the mouse, thereby giving the browser the opportunity to display its own title before giving control back to the script. Tooltip scripts based on mouseovers, as opposed to mousepoints, do not suffer from this race condition. Note that traditional browser-implemented tooltips are also triggered by mouspoints rather than mouseovers.

Like other examples in this document, this is a pedagogical example. More meaningful examples may be found in a transliteration of the Lord's Prayer from the Classical Greek.

Annotation References

One can also include an annotation by reference. This approach is needed for longer annotations. An annotation reference begins with "#" followed by the id of a the actual annotation:

Page notes are cool.

really cool

[target] [annotation] [formatting]

  .hide { display:none; background-color: #FFFFAA }
  Page notes are 
     <span class="red-target" anno="#reallyCool">cool</span>
  <div id="reallyCool" class="hide">really <i>cool</i></div>

The top-level node in the annotation is discarded when it is incorporated into the tooltip.

In this example, the annotation is a short title, but annotations may be as long as several paragraphs. Moreover, it is possible to have nested tooltips in which a tooltip annotation contains a tooltip target, as in the following example:

Page notes are cool. really

[target] [annotations]

  Page notes are 
     <span class="red-target" anno="#reallyCool2">cool</span>.
  <span id="reallyCool2" class="hide">
    <i><a class="red-target" anno="adverb">really</a></i><br>
    <a class="red-target" anno="adjective">cool</a>

This example could be made more interesting by formatting the nested tooltips differently, which brings us to our next topic.


A tooltip skin is an identified block-style HTML object that contains a <var> element. When the tooltip is displayed, the tooltip skin is displayed with the <var> element replaced by the tooltip annotation. A particular skin may be invoked in a tooltip by including its id in the class name of the target, like so:

Page notes are cool.

[target] [skin]

  <div id="cool-skin" class="hide"
     style="background-color: #E6F0FF;
        border: 1px #999999 solid; padding: 0px 4px 2px 4px">
     <var>cool-skin: skin used for cool annotations</var>

Since the var element will be replaced with an annotation, its contents may be used for documentation.

  Page notes are <span class="red-target cool-skin"
cool: skin used for cool annotations

Of course, the notation is more concise if the same class name is used for both the target formatting and the tooltip skin. This is the approach taken in the remaining examples.

A tooltip skin may meaningfully contain more than one <var> element, allowing for multi-part annotations. If the skin has n <var> elements, the annotation should contain an HTML fragment consisting of n HTML objects. The case where n = 2 is useful in discussing, e.g., literal translations from French to English. We may want to annotate each word of the translation with (a) the French term that it came from, and (b) alternate English translations for that French term. In this case, the French-English annotations form a simple lexicon, as in the following example:

Skin with id "French-English":

1. English definition
0. French term

placement: above -2 target

Notice that the variables can be numbered in order to specify the order in which they are read; this is a partial exception to the rule that the contents of <var> elements is irrelevant.

See below for an explanation of the placement specification.

<div class="hide">
<div id="of">
   <i>de</i> <span>from, of, out of, upon</span></div>
<div id="the">
   <i>les</i> <span>the, them</span></div>
<div id="notes">
   <i>notes</i> <span>notes, marks</span></div>
<div id="page">
   <i>page</i> <span>page</span></div>
<div id="are">
   <i>sont</i> <span>are</span></div>
<div id="cool">
   <i>sympa</i> <span>nice, friendly, good, cool</span></div>
de from, of, out of, upon
les the, them
notes notes, marks
page page
sont are
sympa nice, friendly, good, cool
Les notes de page sont sympa

The notes of page are cool.

[targets] [annotations] [template] [formatting]

  .French-English { color:#318CE7; cursor:default }
  .French-English:hover {
     color:#419CFF; position:relative; left:1px; top:1px }
  <a class="French-English" anno="#the">The</a>
  <a class="French-English" anno="#notes">notes</a>
  <a class="French-English" anno="#of">of</a>
  <a class="French-English" anno="#page">page</a>
  <a class="French-English" anno="#are">are</a>
  <a class="French-English" anno="#cool">cool</a>.

Placement Attributes

If present, the placement specification directly follows the tooltip skin. It is a div element whose contents have the following format:

placement: [indent m][above|below [n]][target container]

Page notes are aligned with the left edge of a target container, with an optional indent m offset.  Positive values of m move the page note m pixels to the right.

Vertical placement is determined as follows: The page note is placed above or below the target container as specified, if there is room; otherwise it is placed below or above, respectively. Positive values of n move the page note away from the target.

Placement may be given relative to any of the following target containers: target (the tooltip target), target-line, target-block, target-row (if the target is in a table), note (if the target is in a containing tooltip), note-line, and cursor (the default).

Because page notes may be placed both above and below a tooltip target, we have the possibility of nested tooltip targets in which one tooltip target contains another tooltip target (not to be confused with nested tooltips),  like so:

Page notes are cool.

[targets] [templates] [formatting]

  .pos { /* part of speech */
     color:#AA0030; cursor:default }
  .pos:hover {
     color:#C90030; position:relative; left:1px }
  .part-of-sentence { 
     text-decoration: underline;
     color: #ADA59E }
  .part-of-sentence:hover { color: #000099 }
  <div id="pos" style="width: 90pt; text-align: left">
     <div style="display: inline-block; border: 1px solid #a1a1a1;
        background:#e6e9FF; border-radius:3px; padding:0px 6px 3px 6px"
        ><var>pos: part of speech</var>
  <div>placement: above -2 indent 1 target</div>

The above pos skin effectively has a maximum width. The transparent outer div has a fixed width, but the visible inner div is "shrink wrapped."

  <div id="part-of-sentence" style="border:1px solid #000033;
     background-color:#F6F8F4; background-image: url('plaid.gif');
     border-radius:3px; padding:0px 6px 3px 6px"><var>
  <div>placement: below 2 indent 1 target</div>
  <span class="part-of-sentence" anno="subject">
     <a class="pos" anno="noun used as adjective">Page</a>
     <a class="pos" anno="noun">notes</a></span>
  <span class="part-of-sentence" anno="predicate">
     <a class="pos" anno="verb">are</a>
     <a class="pos" anno="adjective">cool</a></span>.
pos: part of speech
placement: above -2 indent 1 target
placement: below 2 indent 1 target

More Templates

The large notes that display source code in this document use the following template:

   <div id="commentary" style="width:6in; border:1px solid #000033;
     text-align:left; background-color:#F6F8F4;
     background-image: url('plaid.gif');
     border-radius:3px; padding:4px 9px 6px 9px">
     <var>commentary: used to present source code</var>
   <div>placement: below 2 target-line</div>

Finally, the title for this article has a page note whose template is transparent:

   <div id="main-title" style="text-align:center; width:6in">
   <div>placement: below 3 target-block</div>

Other Tooltip Mechanisms

Many tooltip scripts are plugins for JavaScript libraries such as jQuery, mootools, prototype, or the Yahoo User Interface (YUI). The following discussion concentrates on stand-alone scripts. Most of these require significant use of user-supplied JavaScript. Many rely on awkward, explict invocations of the mouseover and mouseout events (e.g., Ajax tooltip, Ashishware tooltips, Dynamic Drive tooltips, JavaScript tooltip, Cool DHTML Tooltip II, Felgall's tooltips, overLIB, texSoft tooltips, Tipster v3.1, wz_tooltip, Zorni tooltips).

Nice Titles uses title attributes and relies on a variant of the mousepoint event, apparently without encountering the above mentioned race condition. Their trick is to programmatically replace the title attributes with "nicetitle" attributes.

Tipster v3.1 uses templates similar to PageNote skins, only the templates are specified in JavaScript variables rather than in the HTML source.

SuperNote allows for nested tooltips and, in fact, can do most of the same things as PageNote tooltips; both scripts work off of ID/CLASS attributes.

OverLIB allows for multi-part annotations in that it allows for annotations with captions. So does SkinnyTip, which is 10K in size.

qTip is only 2K in size; it enhances a document's title attribute. ScriptTiny tooltips are also only 2K in size.

Google's ui.tooltip takes the cake for sheer complexity - but it's very well structured.

Some scripts offer balloon style tooltips, including the Dynamic Drive balloon tooltips and Walter Zorn's extensions. But in the Page Notes approach, ballooniness is a property of the tooltip template rather than the tooltip script; see PageNote Balloon tooltips.

PageNote tooltips are unique in that none of the other tooltip scripts provide for simultaneous triggering of nested tooltip targets. PageNote tooltips are also unusual in that they are free and are highly configurable without resort to user-supplied JavaScript. Unlike many other scripts, PageNote tooltips does not support "clickable" tooltips.


Post a comment

commentary: used to present source code
placement: below 2 target-line