Support for extensions using XUL/XPCOM or the Add-on SDK was removed in Firefox 57, released November 2017. As there is no supported version of Firefox enabling these technologies, this page will be removed by December 2020.

Add-ons using the techniques described in this document are considered a legacy technology in Firefox. Don't use these techniques to develop new add-ons. Use WebExtensions instead. If you maintain an add-on which uses the techniques described here, consider migrating it to use WebExtensions.

Starting from Firefox 53, no new legacy add-ons will be accepted on addons.mozilla.org (AMO) for desktop Firefox and Firefox for Android.

Starting from Firefox 57, only extensions developed using WebExtensions APIs will be supported on Desktop Firefox and Firefox for Android.

Even before Firefox 57, changes coming up in the Firefox platform will break many legacy extensions. These changes include multiprocess Firefox (e10s), sandboxing, and multiple content processes. Legacy extensions that are affected by these changes should migrate to use WebExtensions APIs if they can. See the "Compatibility Milestones" document for more information.

A wiki page containing resources, migration paths, office hours, and more, is available to help developers transition to the new technologies.


Deprecated in Firefox 29 and removed in Firefox 38.

Warning: this tutorial relies on the since-removed Widget API and no longer works with Firefox.

The widget API is deprecated from Firefox 29 onwards. Please see the ui module for replacements. In particular, for a simple button, try the action button or toggle button APIs, and for a more complex widget try the toolbar or sidebar APIs.

The annotator uses content scripts to build user interfaces, get user input, and examine the DOM of pages loaded by the user.

Meanwhile the main module contains the application logic and mediates interactions between the different SDK objects.

We could represent the basic interactions between the main module and the various content scripts like this:

User Interface

The annotator's main user interface consists of a widget and three panels.

  • The widget is used to switch the annotator on and off, and to display a list of all the stored annotations.
  • The annotation-editor panel enables the user to enter a new annotation.
  • The annotation-list panel shows a list of all stored annotations.
  • The annotation panel displays a single annotation.

Additionally, we use the notifications module to notify the user when the add-on's storage quota is full.

Working with the DOM

We'll use two page-mods to interact with the DOMs of pages that the user has opened.

  • The selector enables the user to choose an element to annotate. It identifies page elements which are eligible for annotation, highlights them on mouseover, and tells the main add-on code when the user clicks a highlighted element.

  • The matcher is responsible for finding annotated elements: it is initialized with the list of annotations and searches web pages for the elements they are associated with. It highlights any annotated elements that are found. When the user moves the mouse over an annotated element the matcher tells the main add-on code, which displays the annotation panel.

Working with Data

We'll use the simple-storage module to store annotations.

Because we are recording potentially sensitive information, we want to prevent the user creating annotations when in private browsing mode. The simplest way to do this is to omit the "private-browsing" key from the add-on's "package.json" file. If we do this, then the add-on won't see any private windows, and the annotator's widget will not appear in any private windows.

Getting Started

Let's get started by creating a directory called "annotator". Navigate to it and type cfx init.

Next, we will implement the widget.