• Skip to main content
  • Select language
  • Skip to search
MDN Web Docs
  • Technologies
    • HTML
    • CSS
    • JavaScript
    • Graphics
    • HTTP
    • APIs / DOM
    • WebExtensions
    • MathML
  • References & Guides
    • Learn web development
    • Tutorials
    • References
    • Developer Guides
    • Accessibility
    • Game development
    • ...more docs
Add-ons
  1. MDN
  2. Mozilla
  3. Add-ons
  4. Overlay extensions
  5. XUL School Tutorial
  6. Adding Events and Commands

Adding Events and Commands

In This Article
  1. Event handlers
    1. Custom events
  2. Broadcasters
  3. Commands

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.

« PreviousNext »

Event handlers

Just like with HTML, most JavaScript code execution is triggered by event handlers attached to DOM elements. The most commonly used event is the onload event, which is used in overlays and other windows to detect when the window has loaded and then run initialization code:

// rest of overlay code goes here.
window.addEventListener(
  "load", function() { XulSchoolChrome.BrowserOverlay.init(); }, false);

You can do something similar with the onunload event, to do any cleanup you may need.

Please read Appendix A for recommendations on how to use the load event to initialize your add-on without having a negative performance impact on Firefox.

Another way to attach event handlers, just like HTML, is to place the handler in the XUL code:

<overlay id="xulschoolhello-browser-overlay"
  onload="XulSchoolChrome.BrowserOverlay.init();"
  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

We prefer the first method because it keeps a better separation of content and behavior. Also, note that the addEventListener method receives the event name without the "on" prefix, while element attributes do have the prefix. There's a long list of events you can listen to, and which you use depend on the situation. Elements only implement the events that are relevant to them, but there are several events that are implemented for most elements. These are some notable events you should keep in mind:

  • oncommand. This is one of the most important and commonly used events in XUL. It's very useful because it represents the most common action for input controls such as menu items, buttons and checkboxes. For a button, it represents the action of the user clicking on it, or focusing it with the keyboard and then pressing the ENTER key. It's an abstraction of the main way to interact with a control element.
  • onselect. Fired when the selection in a tree or listbox changes.
  • onclick. Triggered when the user clicks on the element, including right clicks. You shouldn't normally use this event to trigger actions on input controls such as buttons. Use oncommand instead.
  • onfocus and onblur. Used when an element receives or loses focus when the user is navigating with the keyboard. You can combine these with -moz-user-focus to add custom focus behavior to elements that normally wouldn't have it.
  • Drag and drop. Drag and drop operations involve several events. Since drag and drop is a complicated thing to manage, there are some high level wrappers that facilitate working with it. Also keep in mind that there are 2 drag and drop APIs, the newest (and preferred) one introduced in Firefox 3.5.

Event handlers can take an event argument, which is an Event object that holds information on the event. You can get information on key modifiers (in case the user was holding a modifier key like Alt while performing the event), screen coordinates for mouse events, and most importantly, the target element for the event. For example:

<button label="&xulschoolhello.defaultGreeting.label;"
  oncommand="XulSchoolChrome.BrowserOverlay.changeGreeting(event);" />

Then on the Javascript code you would have something like this:

changeGreeting : function(aEvent) {
  // more stuff
  aEvent.target.setAttribute("label", someNewGreeting);
}

The target in this example is the button element, so clicking on it will change its text. The advantage of using the event argument is that the method is not dependent of the specific button, so it can also be used for other elements.

For more advanced event handling, you should read about Event Propagation. In a nutshell, events propagate from the root of the DOM tree all the way down to the target element and then all the way up back to the root, in the capture and bubble phases, respectively. You can capture and cancel events during any of these phases, provided that they aren't canceled before they reach the point where you intended to capture them. The addEventListener method allows you to control the phase where you want to handle an event, with the last argument of the function.

In general, you should avoid adding event handlers in the capturing phase, or canceling events. This can lead to unexpected behavior for the user since most events have a default behavior associated to them.

Custom events

This is a very powerful tool that you should know, even if it isn't that frequently used. The DOM createEvent function allows you to create custom events that you can dispatch and capture.

Custom events serve as a good communication mechanism, specially when dealing with a somewhat common problem: communication between window XUL and web page content. It isn't hard for XUL code to control the content on pages being loaded or displayed, as we will see later on, but it can be hard for your extension XUL code to receive information from pages in a secure manner. This is because it would be very insecure to have a website JS controlling the behavior of Firefox and running JavaScript code with chrome privileges.

Suppose your extension interacts with pages from a website, and you want some actions on this site to trigger actions in your extension. One way to solve this is to have the actions on the site to generate a custom event that can be easily recognized by your extension. You can capture the events in the XUL  overlay, since they'll bubble all the way up:

// in the overlay code.
document.addEventListener(
  "XSHelloGreetingEvent", function(aEvent) { /* do stuff*/ }, false);

Be careful when doing this! You should at least validate the URL of the page that is generating the custom event, so that you know that it's coming from the right place. You should also avoid this kind of events to trigger actions that could be destructive to the user's data, because a malicious site could try to trigger these events and cause damage. There's a reason for the division between remote content and local chrome, so make sure you respect it.

There's a section further ahead on Intercepting Page Loads which complements this section very well. This should give you a solid foundation to handle interaction between web content and XUL.  Additional information on custom events and how they can be used to effect communication between web content and XUL can be found in the Interaction between privileged and non-privileged pages code snippets, which describe and provide examples of this sort of communication.

Broadcasters

Keeping a consistent UI is another important aspect of extension behavior. Maybe your extension needs to disable or enable a series of controls when the user logs in or out of a service, or when Firefox detects it's online or offline. It's common that you need to change several elements at the same time, and this can be difficult to manage through JavaScript. The broadcaster element can help you out in these cases.

First you need to add a broadcaster element to your XUL code, as a child of a broadcasterset element.

<broadcasterset id="xulschoolhello-broadcasterset">
  <broadcaster id="xulschoolhello-online-broadcaster" />
</broadcasterset>

These elements are completely invisible, so you can put them anywhere. It is recommended that you have them at the top of the XUL code, along with script declarations and other invisible elements with as popupset and commandset.

Then you need to identify which of your XUL elements will be linked to this broadcaster, using the observes attribute:

<menuitem id="xulschoolhello-hello-menu-item"
  label="&xulschoolhello.hello.label;"
  accesskey="&xulschoolhello.helloItem.accesskey;"
  observes="xulschoolhello-online-broadcaster"
  oncommand="XULSchoolChrome.BrowserOverlay.sayHello(event);" />

The attribute value is set to be the id of the broadcaster element, indicating that this element will observe all attribute changes that happen in the broadcaster. You can have as many elements as you want observing a broadcaster.

With that set, all you need to do now is set or remove attributes in the broadcaster using JavaScript. All nodes observing it will automatically have those attribute values set or removed as well. You can override pre-existing values, such as the label attribute value in the example.

let onlineBroadcaster = document.getElementById("xulschoolhello-online-broadcaster");
onlineBroadcaster.setAttribute("label", "Something");

You can also have finer-grained control to this behavior by adding the observes element as a child to your observer node. This allows you to choose which attributes you want it to observe.

Broadcasters allow you to easily maintain consistency among numerous elements without having to add much code. They also save you the trouble of having to know if a given element is present in the DOM or not. For example, if you have a customizable toolbar, you can't be sure if a given button is present or not, so it's easier to use a broadcaster. This way you only need to set values to the broadcaster instead of having to check if the button is there or not.

Commands

The command element is a specialized type of broadcaster, meant to be used with the oncommand event. This is the recommended way of centralizing common UI behavior in Firefox and extensions. Commands are heavily used in Firefox, as a quick look into the DOM Inspector should show.

Their behavior is identical as broadcaster elements, but they should be used when oncommand is one of the shared attributes. Our menu example is in fact better suited for a command.

<commandset id="xulschoolhello-commandset">
  <command id="xulschoolhello-hello-command"
    oncommand="XULSchoolChrome.BrowserOverlay.sayHello(event);" />
  <!-- More commands. -->
</commandset>
<!-- More code here... -->
<menuitem id="xulschoolhello-hello-menu-item"
  label="&xulschoolhello.hello.label;"
  accesskey="&xulschoolhello.helloItem.accesskey;"
  command="xulschoolhello-hello-command" />

Commands allow you to keep your JavaScript calls in a single place, avoiding code repetition and possible bugs. Your UI can easily scale this way. You can create an extension that adds toolbar buttons, statusbar buttons and menu items, all with equivalent behavior, and without having to repeat lots of XUL code in the process. Commands and broadcasters also facilitate working with complex form windows and dialogs. You should always keep them in mind when adding the event-driven code for your extension.

« PreviousNext »

This tutorial was kindly donated to Mozilla by Appcoast.

Document Tags and Contributors

Tags: 
  • Add-ons
  • CodingScripting
  • DOM
  • events
  • Glossary
  • Guide
  • JavaScript
  • XUL
 Contributors to this page: wbamberg, dkocho4, mponeto, Zorbing, teoli, Jorge.villalobos, xplosionist, DaveG
 Last updated by: wbamberg, Jul 4, 2016, 1:40:46 PM
See also
  1. WebExtensions
  2. Getting started
    1. What are WebExtensions?
    2. Your first WebExtension
    3. Your second WebExtension
    4. Anatomy of a WebExtension
    5. Example WebExtensions
  3. How to
    1. Intercept HTTP requests
    2. Modify a web page
    3. Add a button to the toolbar
    4. Implement a settings page
  4. Concepts
    1. Using the JavaScript APIs
    2. User interface components
    3. Content scripts
    4. Match patterns
    5. Internationalization
    6. Content Security Policy
    7. Native messaging
  5. Porting
    1. Porting a Google Chrome extension
    2. Porting a legacy Firefox add-on
    3. Embedded WebExtensions
    4. Comparison with the Add-on SDK
    5. Comparison with XUL/XPCOM extensions
    6. Chrome incompatibilities
  6. Firefox workflow
    1. Temporary Installation in Firefox
    2. Debugging
    3. Getting started with web-ext
    4. web-ext command reference
    5. WebExtensions and the Add-on ID
    6. Publishing your WebExtension
  7. JavaScript APIs
    1. Browser support for JavaScript APIs
    2. alarms
    3. bookmarks
    4. browserAction
    5. browsingData
    6. commands
    7. contextMenus
    8. contextualIdentities
    9. cookies
    10. downloads
    11. events
    12. extension
    13. extensionTypes
    14. history
    15. i18n
    16. identity
    17. idle
    18. management
    19. notifications
    20. omnibox
    21. pageAction
    22. runtime
    23. sessions
    24. sidebarAction
    25. storage
    26. tabs
    27. topSites
    28. webNavigation
    29. webRequest
    30. windows
  8. Manifest keys
    1. applications
    2. author
    3. background
    4. browser_action
    5. chrome_url_overrides
    6. commands
    7. content_scripts
    8. content_security_policy
    9. default_locale
    10. description
    11. developer
    12. homepage_url
    13. icons
    14. manifest_version
    15. name
    16. omnibox
    17. options_ui
    18. page_action
    19. permissions
    20. short_name
    21. sidebar_action
    22. version
    23. web_accessible_resources
  9. Add-on SDK
  10. Getting started
    1. Installation
    2. Getting started
    3. Troubleshooting
  11. High-Level APIs
    1. addon-page
    2. base64
    3. clipboard
    4. context-menu
    5. hotkeys
    6. indexed-db
    7. l10n
    8. notifications
    9. page-mod
    10. page-worker
    11. panel
    12. passwords
    13. private-browsing
    14. querystring
    15. request
    16. selection
    17. self
    18. simple-prefs
    19. simple-storage
    20. system
    21. tabs
    22. timers
    23. ui
    24. url
    25. webextension
    26. widget
    27. windows
  12. Low-Level APIs
    1. /loader
    2. chrome
    3. console/plain-text
    4. console/traceback
    5. content/content
    6. content/loader
    7. content/mod
    8. content/symbiont
    9. content/worker
    10. core/heritage
    11. core/namespace
    12. core/promise
    13. dev/panel
    14. event/core
    15. event/target
    16. frame/hidden-frame
    17. frame/utils
    18. fs/path
    19. io/byte-streams
    20. io/file
    21. io/text-streams
    22. lang/functional
    23. lang/type
    24. loader/cuddlefish
    25. loader/sandbox
    26. net/url
    27. net/xhr
    28. places/bookmarks
    29. places/favicon
    30. places/history
    31. platform/xpcom
    32. preferences/event-target
    33. preferences/service
    34. remote/child
    35. remote/parent
    36. stylesheet/style
    37. stylesheet/utils
    38. system/child_process
    39. system/environment
    40. system/events
    41. system/runtime
    42. system/unload
    43. system/xul-app
    44. tabs/utils
    45. test/assert
    46. test/harness
    47. test/httpd
    48. test/runner
    49. test/utils
    50. ui/button/action
    51. ui/button/toggle
    52. ui/frame
    53. ui/id
    54. ui/sidebar
    55. ui/toolbar
    56. util/array
    57. util/collection
    58. util/deprecate
    59. util/list
    60. util/match-pattern
    61. util/object
    62. util/uuid
    63. window/utils
  13. Firefox for Android
  14. Getting started
    1. Walkthrough
    2. Debugging
    3. Code snippets
  15. APIs
    1. Accounts.jsm
    2. BrowserApp
    3. HelperApps.jsm
    4. Home.jsm
    5. HomeProvider.jsm
    6. JavaAddonManager.jsm
    7. NativeWindow
    8. Notifications.jsm
    9. PageActions.jsm
    10. Prompt.jsm
    11. RuntimePermissions.jsm
    12. Snackbars.jsm
    13. Sound.jsm
    14. Tab
  16. Legacy
  17. Restartless extensions
    1. Overview
  18. Overlay extensions
    1. Overview
  19. Themes
  20. Lightweight themes
    1. Overview
  21. Complete themes
    1. Overview
  22. Publishing add-ons
  23. Guides
    1. Signing and distribution overview
    2. Submit an add-on
    3. Review policies
    4. Developer agreement
    5. Featured add-ons
    6. Contact addons.mozilla.org
  24. Community and support
  25. Channels
    1. Add-ons blog
    2. Add-on forums
    3. Stack Overflow
    4. Development newsgroup
    5. IRC Channel