HTML in XUL for rich tooltips

This example demonstrates the dynamic injection of HTML into a XUL element. Specifically, we create a rich tooltip that uses HTML instead of plain text.

Dynamic HTML in XUL Tooltip

Insert the appropriate code from below into your XUL overlay. This example is what the final XUL overlay could look like, assuming a JavaScript overlay titled overlay.js:

<?xml version="1.0" encoding="UTF-8"?>
<overlay id="htmltip-overlay"
    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
    xmlns:html="http://www.w3.org/1999/xhtml">
  <script type="application/x-javascript" src="overlay.js"/>

  <popup id="contentAreaContextMenu">
    <menuitem id="htmltip1" label="foo1"
        onmouseover="htmltip.onMouseTooltip(event)"
        tooltip="myHTMLTip"
        />
    <menuitem id="htmltip2" label="foo2"
        onmouseover="htmltip.onMouseTooltip(event)"
        tooltip="myHTMLTip"
        />
  </popup>

  <popupset id="mainPopupSet">
        <tooltip id="myHTMLTip">
            <html:div id="myHTMLTipDiv" type="content"/>
        </tooltip>
  </popupset>



</overlay>

Insert your version of the following into the JavaScript overlay. Our customized tooltipHTML attribute for each element can be set at any time.

var htmltip = {

onLoad: function() {
	//at any point you can save an HTML string to a XUL attribute for later injection into the tooltip
	document.getElementById("htmltip1").setAttribute("tooltipHTML", "<font color='red'>red foo</font>")
	document.getElementById("htmltip2").setAttribute("tooltipHTML", "<font color='green'>green foo</font>")
		
},

onMouseTooltip: function(event) {

//get the HTML tooltip string assigned to the element that the mouse is over (which will soon launch the tooltip)
var txt = event.target.getAttribute("tooltipHTML");

// get the HTML div element that is inside the custom XUL tooltip
var div = document.getElementById("myHTMLTipDiv");

//clear the HTML div element of any prior shown custom HTML
while(div.firstChild)
	div.removeChild(div.firstChild);

//safely convert HTML string to a simple DOM object, stripping it of JavaScript and more complex tags
var injectHTML = Components.classes["@mozilla.org/feed-unescapehtml;1"]
.getService(Components.interfaces.nsIScriptableUnescapeHTML)
.parseFragment(txt, false, null, div);

//attach the DOM object to the HTML div element
div.appendChild(injectHTML);

}

}

window.addEventListener('load', htmltip.onLoad, false);

In the XUL overlay, xmlns:html is used to enable HTML tags to be used inside the XUL. Our enhanced XUL tooltip is an element that is written ahead of time, and it contains an HTML div element whose type attribute lowers its privileges to being that content element, although it is an element of chrome. This is recommended for security reasons, especially if remote HTML is to be inserted.

A number of menuitems have a tooltip attribute pointing to the same tooltip. That tooltip is empty now, but we will use the mouseover event to dynamically populate the tooltip (which is about to be shown) with a different message for each menuitem. This is done by calling the onMouseTooltip function, which will take the tooltipHTML attribute of the element that is being hovered over and safely convert that into DOM and inject it into the tooltip that will soon be shown. The tooltipHTML attribute is an HTML string which is set sometime beforehand for each element. For security reasons, the conversion will strip out some of the more dangerous elements in the HTML string, like JavaScript and iframes.

Non-dynamic HTML in XUL tooltip

It is also possible to avoid using dynamic HTML to accomplish this. You would have to have a separate XUL tooltip element assigned to each element that you wish to have a rich tooltip with. You should write the HTML straight into the XUL.

<?xml version="1.0" encoding="UTF-8"?>
<overlay id="htmltip-overlay"
    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
    xmlns:html="http://www.w3.org/1999/xhtml">
  <script type="application/x-javascript" src="overlay.js"/>

  <popup id="contentAreaContextMenu">
    <menuitem id="htmltip3" label="foo3"
        tooltip="mytip3html"
        />
  </popup>

  <popupset id="mainPopupSet">
        <tooltip id="mytip3html">
            <html:div type="content">
                <html:b>bold foo</html:b>
            </html:div>
        </tooltip>
  </popupset>
</overlay>