Out of the box notifications in Firefox as far as extension developers are concerned are pretty blend. You can only set icon and text, which is enough in most of the cases; however while working on New Tab JumpStart extension I wanted to show more than that.
I wanted to show list of all search engines in Firefox. One of the suggested solutions requires manual control over animation, persistence counting, styling, etc. So I tried to see if there was a simpler or at least more elegant solution. And, I might have found it.
1) Get notification box and add notification
2) Replace notification body with custom binding
Should be simple as that. So here’s a short snippet for doing that (see below for the full code reference, this is just a cut out showing principle):
var nb = getBrowserWindow().getNotificationBox(window);
var n = nb.getNotificationWithValue('jumpstart_searchnotice');
if(!n){
nb.appendNotification('', 'jumpstart_searchnotice',
'chrome://jumpstart/skin/img/JumpStart32.png',
nb.PRIORITY_INFO_HIGH, []);
n = nb.getNotificationWithValue('jumpstart_searchnotice');
var p = n.ownerDocument.getAnonymousElementByAttribute(n, 'anonid', 'details');
var bx = n.ownerDocument.createElement('hbox');
bx.setAttribute('style', '-moz-binding: url("chrome://jumpstart/content/bindings/thumbnail.xml#searchEngines");');
bx.setAttribute('flex', '1');
p.parentNode.replaceChild(bx, p);
}
n.persistence = 10;
Full code how it’s used in the extension is in tabView.js search for showSearchNotice function.
getBrowserWindow is getting current browser window so we can get notificationbox . Then we are getting or creating the notice. Text doesn’t really matter since it’s going to be replaced anyway.
var p = n.ownerDocument.getAnonymousElementByAttribute(n, 'anonid', 'details');
This part is crucial since that is the element we are going to replace (it’s parent is container we really want but it doesn’t have a suitable attribute to get it). Note though that ownerDocument should be used to get element or create new element since it is not the same document as page’s – it’s really chrome window’s document.
bx.setAttribute('style', '-moz-binding: url("chrome://jumpstart/content/bindings/thumbnail.xml#searchEngines");');
This is also important since this way we’re adding custom binding to the notification. If XUL markup is complex this is much easier to do than adding children manually.
Note as well at the end how properties of notification can be still controlled and Firefox handles them correctly.
Here’s a snippet of the XBL binding:
<binding id="searchEngines">
<resources>
<stylesheet src="chrome://jumpstart/skin/tabView.css"/>
<stylesheet src="chrome://jumpstart/skin/xbl.css"/>
<!--<stylesheet src="chrome://jumpstart/skin/overlay.css"/>-->
</resources>
<content>
<xul:hbox class="searchEngines">
<xul:spacer flex="1" />
<xul:arrowscrollbox anonid="searchEnginesContainer" flex="1"></xul:arrowscrollbox>
<xul:spacer flex="1" />
<xul:label class="customlink" value="&back;" onclick="loadURI('chrome://jumpstart/content/tabView.xul', null, null, true);" />
</xul:hbox>
</content>
<implementation>
...
That is snippet from thumbnails.xml search for id=“searchEngines”. Basically, further in the implementation I’m just enumerating all search engines, that’s why the content doesn’t look like contains much.
And the final result of this is:

Oh, yes, some final thoughts. This seems to be more elegant solution than what was suggested on MDN however this might break if Firefox developers decide to change layout of notifications in future. That being said this works in both 3.6 and 4.0 beta versions so I don’t expect it to change soon.
And another thing, CSS is applied incorrectly by Firefox so broader CSS selector is applied after more specific one. Note customlink class in content of the XBL, that was applied before label style which doesn’t make sense at all. That was effectively breaking my styling so I had to add the styling to my overlay.css which I didn’t feel like. My overlay.css is added as overlay to the browser itself so I suppose binding’s overlay is applied first regardless of specificity of CSS selectors and that seems to be completely wrong but what can you do. Anyway, just so you know and not waste hours in frustration.