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 addons.mozilla.org (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.

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.

Create a simple user interface for an add-on in Firefox's add-on bar.

Usage

"Widgets" are small pieces of content that live in the Firefox 4 add-on bar. They can be simple icons or complex web pages. You can attach panels to them that open when they're clicked, or you can define a custom click handler to perform some other action, like opening a web page in a tab.

There are a few advantages to using widgets over an ad hoc user interface. First, your users will be accustomed to interacting with add-ons via widgets and the add-on bar. Second, it allows Firefox to treat your interface as a first-class citizen. For example, in the future Firefox may allow the user to drag widgets from the add-on bar to other toolbars. By exposing your interface as a widget, your add-on would automatically inherit such functionality.

Creation and content

Widgets can contain images or arbitrary web content. You can include this content inline as a string by using the content property, or point to content using a URL with the contentURL property.

Upon creation, the widget is automatically added to the add-on bar. You can set the width of a widget, but the height is fixed so as to fit in the add-on bar. If the content is an image, it is automatically scaled to be 16x16 pixels.

For example, this widget contains an image, so it looks like a simple icon:

require("sdk/widget").Widget({
  id: "mozilla-icon",
  label: "My Mozilla Widget",
  contentURL: "http://www.mozilla.org/favicon.ico"
});

You can make contentURL point to an HTML or icon file which you have packaged inside your add-on. Just save the file in your add-on's data directory, and reference it using the data.url() method of the self module:

var data = require("sdk/self").data;
require("sdk/widget").Widget({
  id: "my-widget",
  label: "My Widget",
  contentURL: data.url("my-content.html")
});

This widget contains an entire web page:

require("sdk/widget").Widget({
  id: "hello-display",
  label: "My Hello Widget",
  content: "Hello!",
  width: 50
});

Widgets are quite small by default, so this example used the width property to grow it in order to show all the text.

Scripting widget content

To interact with the widget's content you need to load a separate script into the panel. In the SDK these scripts are called "content scripts" because they're explicitly used for interacting with web content.

While content scripts can access the content they're attached to, they can't use the SDK's APIs. So implementing a complete solution usually means you have to send messages between the content script and the main add-on code.

  • You can specify one or more content scripts to load into the widget using the contentScript or contentScriptFile options to the Widget() constructor.

  • You can communicate with the script using either the postMessage() API or (preferably, usually) the port API.

Unless your content script is extremely simple and consists only of a static string, don't use contentScript: if you do, you may have problems getting your add-on approved on AMO.

Instead, keep the script in a separate file and load it using contentScriptFile. This makes your code easier to maintain, secure, debug and review.

For example, suppose we want to implement a media player as an add-on. We could implement the main user interface as a widget hosting an array of buttons to control play/pause/stop functions.

We can then use a content script to listen for clicks on those buttons. But because content scripts can't use the SDK's APIs, we'll want the content script to send messages to the main add-on code, which can then implement the media player functions using the SDK.

The widget's content is specified using HTML like this:

<html>
  <body>
    <img src="play.png" id="play-button">
    <img src="pause.png" id="pause-button">
    <img src="stop.png" id="stop-button">
  </body>
</html>

We just include three icons, and assign an ID to each one. This HTML file, and the icon files it references, are saved in the add-on's data directory.

Next, we write a content script that listens for click events on each icon and sends the corresponding message to the main add-on code:

var play_button = document.getElementById("play-button");
play_button.onclick = function() {
  self.port.emit("play");
}
var pause_button = document.getElementById("pause-button");
pause_button.onclick = function() {
  self.port.emit("pause");
}
var stop_button = document.getElementById("stop-button");
stop_button.onclick = function() {
  self.port.emit("stop");
}

We save this file in the add-on's data directory as "button-script.js". Finally. in the add-on's "main.js" file, we create the widget, assign it the HTML file and the content script, and listen for events from the content script:

const widgets = require("sdk/widget");
const data = require("sdk/self").data;
var player = widgets.Widget({
  id: "player",
  width: 72,
  label: "Player",
  contentURL: data.url("buttons.html"),
  contentScriptFile: data.url("button-script.js")
});
player.port.on("play", function() {
  console.log("playing");
});
player.port.on("pause", function() {
  console.log("pausing");
});
player.port.on("stop", function() {
  console.log("stopping");
});

To learn much more about content scripts, see the Working with Content Scripts guide.

Scripting trusted widget content

We've already seen that you can package HTML files in your add-on's data directory and use them to define the widget's content. We can call this "trusted" content, because unlike content loaded from a source outside the add-on, the add-on author knows exactly what it's doing. To interact with trusted content you don't need to use content scripts: you can just include a script from the HTML file in the normal way, using script tags.

Like a content script, these scripts can communicate with the add-on code using the postMessage() API or the port API. The crucial difference is that these scripts access the postMessage and port objects through the addon object, whereas content scripts access them through the self object.

To show the difference, convert the player add-on above to use normal page scripts instead of content scripts.

First, in the content script, change self to addon, and wrap it in a function:

function init() {
  var play_button = document.getElementById("play-button");
  play_button.onclick = function() {
    addon.port.emit("play");
  }
  var pause_button = document.getElementById("pause-button");
  pause_button.onclick = function() {
    addon.port.emit("pause");
  }
  var stop_button = document.getElementById("stop-button");
  stop_button.onclick = function() {
    addon.port.emit("stop");
  }
}

Next, add a script tag to reference "button-script.js", and call its init() function on load:

<html>
  <head>
    <script src="button-script.js"></script>
  </head>
  <body onLoad="init()">
    <img src="play.png" id="play-button">
    <img src="pause.png" id="pause-button">
    <img src="stop.png" id="stop-button">
  </body>
</html>

Finally, remove the line attaching the content script from "main.js":

const widgets = require("sdk/widget");
const data = require("sdk/self").data;
var player = widgets.Widget({
  id: "player",
  width: 72,
  label: "Player",
  contentURL: data.url("buttons.html")
});
player.port.emit("init");
player.port.on("play", function() {
  console.log("playing");
});
player.port.on("pause", function() {
  console.log("pausing");
});
player.port.on("stop", function() {
  console.log("stopping");
});

Attaching panels to widgets

You can supply a panel to the widget's constructor: if you do this, the panel is automatically displayed when the user clicks the widget.

data = require("sdk/self").data
var clockPanel = require("sdk/panel").Panel({
  width:215,
  height:160,
  contentURL: data.url("clock.html")
});
require("sdk/widget").Widget({
  id: "open-clock-btn",
  label: "Clock",
  contentURL: data.url("History.png"),
  panel: clockPanel
});

Note that this is, at the moment, the only way you can attach a panel to a widget.

You must supply the panel in the widget's constructor for it to work. If you assign the panel to the widget after construction, the panel can still be shown but will not be anchored to the widget:

data = require("sdk/self").data
var clockPanel = require("sdk/panel").Panel({
  width:215,
  height:160,
  contentURL: data.url("clock.html")
});
widget = require("sdk/widget").Widget({
  id: "open-clock-btn",
  label: "Clock",
  contentURL: data.url("History.png")
});
widget.panel = clockPanel;
// Will not be anchored
widget.panel.show();

Also, if you try to call panel.show() inside your widget's click event listener, the panel will not be anchored:

data = require("sdk/self").data
var clockPanel = require("sdk/panel").Panel({
  width:215,
  height:160,
  contentURL: data.url("clock.html")
});
require("sdk/widget").Widget({
  id: "open-clock-btn",
  label: "Clock",
  contentURL: data.url("History.png"),
  panel: clockPanel,
  onClick: function() {
    // Will not be anchored
    this.panel.show();
  }
});

See bug 638142.

Private windows

If your add-on has not opted into private browsing, then your widget will not appear in any private browser windows.

To learn more about private windows, how to opt into private browsing, and how to support private browsing, refer to the documentation for the private-browsing module.

Examples

For conciseness, these examples create their content scripts as strings and use the contentScript property. In your own add-ons, you will probably want to create your content scripts in separate files and pass their URLs using the contentScriptFile property. See Working with Content Scripts for more information.

var widgets = require("sdk/widget");
// A basic click-able image widget.
widgets.Widget({
  id: "google-link",
  label: "Widget with an image and a click handler",
  contentURL: "http://www.google.com/favicon.ico",
  onClick: function() {
    require("sdk/tabs").activeTab.url = "http://www.google.com/";
  }
});
// A widget that changes display on mouseover.
widgets.Widget({
  id: "mouseover-effect",
  label: "Widget with changing image on mouseover",
  contentURL: "http://www.yahoo.com/favicon.ico",
  onMouseover: function() {
    this.contentURL = "http://www.bing.com/favicon.ico";
  },
  onMouseout: function() {
    this.contentURL = "http://www.yahoo.com/favicon.ico";
  }
});
// A widget that updates content on a timer.
widgets.Widget({
  id: "auto-update-widget",
  label: "Widget that updates content on a timer",
  content: "0",
  contentScript: 'setTimeout(function() {' +
                 '  document.body.innerHTML++;' +
                 '}, 2000)',
  contentScriptWhen: "ready"
});
// A widget created with a specified width, that grows.
var myWidget = widgets.Widget({
  id: "widget-effect",
  label: "Wide widget that grows wider on a timer",
  content: "I'm getting longer.",
  width: 50,
});
require("sdk/timers").setInterval(function() {
  myWidget.width += 10;
}, 1000);
// A widget communicating bi-directionally with a content script.
var widget = widgets.Widget({
  id: "message-test",
  label: "Bi-directional communication!",
  content: "<foo>bar</foo>",
  contentScriptWhen: "ready",
  contentScript: 'self.on("message", function(message) {' +
                 '  alert("Got message: " + message);' +
                 '});' +
                 'self.postMessage("ready");',
  onMessage: function(message) {
    if (message == "ready")
      widget.postMessage("me too");
  }
});

Globals

Constructors

Widget(options)

Creates a new widget. The widget is immediately added to the add-on bar.

Parameters

options : object
Required options:

Name Type  
label string

A string description of the widget used for accessibility, title bars, and error reporting.

id string

A string used to identify your widget in order to save its location when the user moves it in the browser. This string has to be unique and must not be changed over time.

Optional options:

Name Type  
content string

An optional string value containing the displayed content of the widget. It may contain HTML. Widgets must have either the content property or the contentURL property set.

If the content is an image, it is automatically scaled to be 16x16 pixels.

contentURL string

An optional string URL to content to load into the widget. This can be local content or remote content, an image or web content. Widgets must have either the content property or the contentURL property set.

If the content is an image, it is automatically scaled to be 16x16 pixels.

panel Panel

An optional panel to open when the user clicks on the widget. Note: If you also register a "click" listener, it will be called instead of the panel being opened. However, you can show the panel from the listener by calling this.panel.show().

width integer

Optional width in pixels of the widget. If not given, a default width is used.

onClick function

Include this to listen to the widget's click event.

onMessage function

Include this to listen to the widget's message event.

onMouseover function

Include this to listen to the widget's mouseover event.

onMouseout function

Include this to listen to the widget's mouseout event.

onAttach function

Include this to listen to the widget's attach event.

tooltip string

Optional text to show when the user's mouse hovers over the widget. If not given, the label is used.

allow object

An optional object describing permissions for the content. It should contain a single key named script whose value is a boolean that indicates whether or not to execute script in the content. script defaults to true.

contentScriptFile string,array

A local file URL or an array of local file URLs of content scripts to load. Content scripts specified by this property are loaded before those specified by the contentScript property.

contentScript string,array

A string or an array of strings containing the texts of content scripts to load. Content scripts specified by this property are loaded after those specified by the contentScriptFile property.

contentScriptWhen string

When to load the content scripts. This may take one of the following values:

  • "start": load content scripts immediately after the document element for the widget is inserted into the DOM, but before the DOM content itself has been loaded
  • "ready": load content scripts once DOM content has been loaded, corresponding to the DOMContentLoaded event
  • "end": load content scripts once all the content (DOM, JS, CSS, images) for the widget has been loaded, at the time the window.onload event fires

This property is optional and defaults to "end".

contentScriptOptions object

Read-only value exposed to content scripts under self.options property.

Any kind of jsonable value (object, array, string, etc.) can be used here. Optional.

Widget

Represents a widget object.

Methods

destroy()

Removes the widget from the add-on bar.

postMessage(data)

Sends a message to the widget's content scripts.

Parameters

data : value
The message to send. The message can be any JSON-serializable value.

on(type, listener)

Registers an event listener with the widget.

Parameters

type : string
The type of event to listen for.

listener : function
The listener function that handles the event.

removeListener(type, listener)

Unregisters an event listener from the widget.

Parameters

type : string
The type of event for which listener was registered.

listener : function
The listener function that was registered.

getView(window)

Retrieve a WidgetView instance of this widget relative to a browser window.

Parameters

window : BrowserWindow
The BrowserWindow instance to match.

Returns

WidgetView : A WidgetView instance associated with the browser window. Any changes subsequently applied to this object will only be applied to the widget attached to that window.

Properties

label

The widget's label. Read-only.

content

A string containing the widget's content. It can contain HTML. Setting it updates the widget's appearance immediately. However, if the widget was created using contentURL, then this property is meaningless, and setting it has no effect.

contentURL

The URL of content to load into the widget. This can point to local content loaded from your add-on's "data" directory or remote content, an image or web content. Setting it updates the widget's appearance immediately. However, if the widget was created using content, then this property is meaningless, and setting it has no effect.

Setting the contentURL property will break the channel of communication between this widget and any content scripts it contains. Messages sent from the content script will no longer be received by the main add-on code, and vice versa. This issue is currently tracked as bug 825434.

panel

A panel to open when the user clicks on the widget.

width

The widget's width in pixels. Setting it updates the widget's appearance immediately.

tooltip

The text of the tooltip that appears when the user hovers over the widget.

allow

A object describing permissions for the content. It contains a single key named script whose value is a boolean that indicates whether or not to execute script in the content.

contentScriptFile

A local file URL or an array of local file URLs of content scripts to load.

contentScript

A string or an array of strings containing the texts of content scripts to load.

contentScriptWhen

When to load the content scripts. This may have one of the following values:

  • "start": load content scripts immediately after the document element for the widget is inserted into the DOM, but before the DOM content itself has been loaded
  • "ready": load content scripts once DOM content has been loaded, corresponding to the DOMContentLoaded event
  • "end": load content scripts once all the content (DOM, JS, CSS, images) for the widget has been loaded, at the time the window.onload event fires

contentScriptOptions

Read-only value exposed to content scripts under self.options property.

Any kind of jsonable value (object, array, string, etc.) can be used here. Optional.

port

Object that allows you to:

  • send events to the content script using the port.emit function
  • receive events from the content script using the port.on function

See the guide to communicating using port for details.

Events

attach

This event is emitted when a browser window is opened and a new WidgetView object is created. If the widget has a content script, this event is fired only when the content script is applied according to the contentScriptWhen attribute.

Arguments

WidgetView : The related WidgetView object.

click

This event is emitted when the widget is clicked.

Arguments

WidgetView : Listeners are passed a single argument which is the WidgetView that triggered the click event.

message

If you listen to this event you can receive message events from content scripts associated with this widget. When a content script posts a message using self.postMessage(), the message is delivered to the add-on code in the widget's message event.

Arguments

value : Listeners are passed a single argument which is the message posted from the content script. The message can be any JSON-serializable value.

mouseover

This event is emitted when the user moves the mouse over the widget.

mouseout

This event is emitted when the user moves the mouse away from the widget.

WidgetView

Represents a widget instance specific to one browser window.

Anything you do to an instance of this object will only be applied to the instance attached to its browser window: widget instances attached to other browser windows will be unaffected.

By contrast, any changes you make to an instance of the normal Widget class will be applied across all browser windows.

This class has all the same methods, attributes and events as the Widget class except for the getView method and the attach event.

In this example WidgetView is used to display different content for http and https schemes:

// A widget that update its content specifically to each window.
var tabs = require("sdk/tabs");
var windows = require("sdk/windows").browserWindows;
var widget = require("sdk/widget").Widget({
  id: "window-specific-test",
  label: "Widget with content specific to each window",
  content: " ",
  width: 50
});
// Observe tab switch or document changes in each existing tab:
function updateWidgetState(tab) {
  var view = widget.getView(tab.window);
  if (!view) return;
  // Update widget displayed text:
  view.content = tab.url.match(/^https/) ? "Secured" : "Unsafe";
}
tabs.on('ready', updateWidgetState);
tabs.on('activate', updateWidgetState);

Methods

destroy()

Removes the widget view from the add-on bar.

postMessage(data)

Sends a message to the widget view's content scripts.

Parameters

data : value
The message to send. The message can be any JSON-serializable value.

on(type, listener)

Registers an event listener with the widget view.

Parameters

type : string
The type of event to listen for.

listener : function
The listener function that handles the event.

removeListener(type, listener)

Unregisters an event listener from the widget view.

Parameters

type : string
The type of event for which listener was registered.

listener : function
The listener function that was registered.

Properties

label

The widget view's label. Read-only.

content

A string containing the widget view's content. It can contain HTML. Setting it updates the widget view's appearance immediately. However, if the widget view was created using contentURL, then this property is meaningless, and setting it has no effect.

contentURL

The URL of content to load into the widget. This can point to local content loaded from your add-on's "data" directory or remote content, an image or web content. Setting it updates the widget's appearance immediately. However, if the widget was created using content, then this property is meaningless, and setting it has no effect.

Setting the contentURL property will break the channel of communication between this widget and any content scripts it contains. Messages sent from the content script will no longer be received by the main add-on code, and vice versa. This issue is currently tracked as bug 825434.

panel

A panel to open when the user clicks on the widget view.

width

The widget view's width in pixels. Setting it updates the widget view's appearance immediately.

tooltip

The text of the tooltip that appears when the user hovers over the widget view.

allow

A object describing permissions for the content. It contains a single key named script whose value is a boolean that indicates whether or not to execute script in the content.

contentScriptFile

A local file URL or an array of local file URLs of content scripts to load.

contentScript

A string or an array of strings containing the texts of content scripts to load.

contentScriptWhen

When to load the content scripts. This may have one of the following values:

  • "start": load content scripts immediately after the document element for the widget view is inserted into the DOM, but before the DOM content itself has been loaded
  • "ready": load content scripts once DOM content has been loaded, corresponding to the DOMContentLoaded event
  • "end": load content scripts once all the content (DOM, JS, CSS, images) for the widget view has been loaded, at the time the window.onload event fires

contentScriptOptions

Read-only value exposed to content scripts under self.options property.

Any kind of jsonable value (object, array, string, etc.) can be used here. Optional.

port

Object that allows you to:

  • send events to the content script using the port.emit function
  • receive events from the content script using the port.on

See the guide to communicating using port for details.

Events

detach

The detach event is fired when the widget view is removed from its related window. This can occur if the window is closed, Firefox exits, or the add-on is disabled.

click

This event is emitted when the widget view is clicked.

message

If you listen to this event you can receive message events from content scripts associated with this widget view. When a content script posts a message using self.postMessage(), the message is delivered to the add-on code in the widget view's message event.

Arguments

value : Listeners are passed a single argument which is the message posted from the content script. The message can be any JSON-serializable value.

mouseover

This event is emitted when the user moves the mouse over the widget view.

mouseout

This event is emitted when the user moves the mouse away from the widget view.

Document Tags and Contributors

Tags: 
 Contributors to this page: wbamberg, Canuckistani, evold
 Last updated by: wbamberg,