User Notifications and Alerts

It is often the case that extensions need to notify users about important events, often requiring some response. Using modal dialogs and alerts is usually a bad idea. They interrupt the user's workflow, demanding immediate action before anything else can be done. Users will find them annoying and probably will learn to dismiss them as quickly as possible without even reading what they have to say. Or they will just get rid of your add-on.

This section lists a few alternatives that give you the possibility of notifying the user and requesting action without being too annoying.

The notificationbox element

You have probably seen these before. The "remember password" prompt is the one that shows up the most often. They are thin boxes that appear from beneath the tab list and above the page content, with some text and maybe a few buttons. This kind of notification is implemented with a notificationbox.

This kind on notification is very easy to implement, it doesn't interrupt the user and is easy to read and dismiss, so it is our recommended way of displaying alerts and notifications. There's a catch, though: these notifications are inside the current tab, so switching tabs will make a notification disappear. The notification shows up again when you come back to the tab that displayed it. This means that these notifications make the most sense when they are related to the page currently being displayed, such as a page trying to install an add-on, or a site you just entered a password on.

Notification boxes are very easy to create, and are very customizable:

let nb = gBrowser.getNotificationBox();
let acceptButton = new Object();
let declineButton = new Object();
let message =
  this._bundle.getString("xulschoolhello.friendMessage.label");
let that = this;

acceptButton.label =
  this._bundle.getString("xulschoolhello.acceptButton.label");
acceptButton.accessKey =
  this._bundle.getString("xulschoolhello.acceptButton.accesskey");
acceptButton.popup = null;
acceptButton.callback = function() { that.acceptRequest(); };
// similarly for decline button.
nb.appendNotification(
  message, "xulschoolhello-friend-notification",
  "chrome://xulschoolhello/skin/friend-notification.png",
  nb.PRIORITY_INFO_HIGH, [ acceptButton, declineButton ]);

All browser tabs have a notification box by default, so you don't need to do any overlaying. The notificationbox elements can be obtained from the gBrowser object. In this case we don't pass any arguments to getNotificationBox so that we get the notification box that corresponds to the tab currently on display. The appendNotification method takes the message, id, image (32x32), level and buttons. The level argument determines the "strength" of the message, indicated by its background color when it is displayed. You should look for the level that better fits your message, and use the lowest applicable level, to prevent the user from getting used to dismissing high-level notifications. The buttons are represented by simple JS data objects. This is all explained in detail in the notificationbox page.

Notification boxes are designed to be easily dismissed. All notifications have an additional close button, so you should take into account that it's possible that none of your custom buttons will be clicked. Also, clicking on any of your custom buttons will cause the notification to be immediately closed, so you should only use notification boxes for single-step processes.

The Alerts Service

This is a very good option when you want to alert users about events without requiring input from them. Alerts are displayed in an OS-specific way, so their look is native. You can associate an action to the user clicking on the alert. Another advantage is that you use an XPCOM service to do this (nsIAlertsService), so you can easily trigger alerts from chrome and non-chrome code. On the other hand, alerts are displayed only temporarily

Using the Alerts Service is similar to using notification boxes:

let alertsService =
  Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
let title = this._bundle.getString("xulschoolhello.greeting.title");
let message = this._bundle.getString("xulschoolhello.greeting.label");

alertsService.showAlertNotification(
  "chrome://xulschoolhello/skin/hello-notification.png",
  title, message, true, "", this, "XULSchool Hello Message");

We pass this as an argument, assuming that this is an object that implements nsIObserver. We do this when we need to handle clicks on the alert box. The image can have any size, but it is recommended that you use a medium, fixed size.

The main disadvantage of using alerts is that support for the Alerts Service is not guaranteed for all platforms and Firefox versions. Support for Windows has existed since Firefox 2. For Mac OS X, support was added on Firefox 3, and only through a third-party tool called Growl. On Linux systems, we have confirmed that it works on Firefox 3 on Ubuntu Linux, but we haven't tested all distributions and Firefox versions.

Because of the inconsistent support and temporary nature of these alerts, we don't recommend using this service to show information the user needs to know and can't get in any other way.

Custom alerts

Creating custom solutions for alerting the user is not complicated, given the advantages of XUL overlays and CSS positioning. However, these solutions are prone to be buggy and have accessibility issues. You should use the 2 alternatives mentioned above whenever possible. If none of those fit your needs then this is an acceptable solution.

An easy way to display alerts is to include a hidden box in your overlay, which you can fill with any content you need before removing the hidden attribute so that it is displayed to the user. The best locations for this kind of box are above and below the tab browser. Below is preferrable because it only cuts the bottom part of the current page, as opposed to pushing down all tabs and content. Notification boxes are a good guideline to what you should aim for: thin, informative and easy to dismiss.

Another option is to also add a hidden box to the overlay, but use CSS positioning to locate it where you want. This usually means that the box will be hovering on top of the page's content, and there are a few things you must know about this. First of all, switching tabs will probably make your alert disappear. This is probably due to the fact that the browser tab box uses a deck internally, and that affects z-indexing. You'll have to code around this using tab events in order to know when to re-display your alert. Another problem you need to take into account is that transparency of floating XUL on the Mac OS version of Firefox 2 doesn't work. You'll end up with a box with a white background you can't get rid of . On Firefox 3 and above, this seems to have been corrected, using the panel element.

The bottom right corner of the browser is the recommended location for an alert, because it normally doesn't block the part of the content where the user is reading, or the most important parts of page content, such as menus and titles.

Remember this is not a recommended practice. Imagine having multiple extensions notifying you in their own custom way, probably even at the same time! This is not good from a UI perspective, so you consider custom alerts the very last resort.

This tutorial was kindly donated to Mozilla by Appcoast.