Implementing the widget

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.

From Firefox 53 onwards, no new legacy add-ons will be accepted on (AMO).

From Firefox 57 onwards, WebExtensions will be the only supported extension type, and Firefox will not load other types.

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 WebExtensions if they can. See the "Compatibility Milestones" document for more.

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.

We want the widget to do two things:

  • On a left-click, the widget should activate or deactivate the annotator.
  • On a right-click, the widget should display a list of all the annotations the user has created.

Because the widget's click event does not distinguish left and right mouse clicks, we'll use a content script to capture the click events and send the corresponding message back to our add-on.

The widget will have two icons: one to display when it's active, one to display when it's inactive.

So there are three files we'll need to create: the widget's content script and its two icons.

Inside the data subdirectory create another subdirectory widget. We'll keep the widget's files here. This hierarchy isn't mandatory; you could just keep them all under data. But it seems tidier this way.

The widget's content script

The widget's content script just listens for left- and right- mouse clicks and posts the corresponding message to the add-on code:

this.addEventListener('click', function(event) {
  if(event.button == 0 && event.shiftKey == false)

  if(event.button == 2 || (event.button == 0 && event.shiftKey == true))
}, true);

Save this in your data/widget directory as widget.js.

The widget's icons

You can copy the widget's icons from here:

Or, if you're feeling creative, you can make your own icons.  Either way, save them in your data/widget directory.


Now in the lib directory open main.js and add the following code:

var widgets = require('sdk/widget');
var data = require('sdk/self').data;

var annotatorIsOn = false;

function toggleActivation() {
  annotatorIsOn = !annotatorIsOn;
  return annotatorIsOn;

exports.main = function() {

  var widget = widgets.Widget({
    id: 'toggle-switch',
    label: 'Annotator',
    contentURL: data.url('widget/pencil-off.png'),
    contentScriptWhen: 'ready',
    contentScriptFile: data.url('widget/widget.js')

  widget.port.on('left-click', function() {
    widget.contentURL = toggleActivation() ?
              data.url('widget/pencil-on.png') :

  widget.port.on('right-click', function() {
      console.log('show annotation list');

The annotator is inactive by default. It creates the widget and responds to messages from the widget's content script by toggling its activation state. Since we don't have any code to display annotations yet, we just log the right-click events to the console.

Now from the annotator directory type cfx run. You should see the widget in the add-on bar:

Left- and right-clicks should produce the appropriate debug output, and a left-click should also change the widget icon to signal that it is active.

Next we'll add the code to create annotations.

Document Tags and Contributors

 Contributors to this page: wbamberg, Canuckistani, Sheppy
 Last updated by: wbamberg,