XUL/XBL Replacement Newsletter 8

This is the eighth edition of the XUL/XBL Replacement Newsletter. Since the last update there’ve been steps towards removing in-content XBL, flexbox performance improvements, and new chrome Custom Element capabilities.

In Content XBL → UA Widgets

We have been using XBL inside web content for a long time for rendering UI like scrollbars. But there are even more complex situations where we use XBL to insert DOM and run JS inside the content document. For example, with <video controls> or <input type="date">.

Tim Guan-tin Chien has been busy working on an alternative to this setup. Now that bug 1484048 has landed, the video controls are working entirely without XBL in nightly builds. Instead, we are using Shadow DOM and JS running inside of a sandbox. The setup is coined “UA Widgets” - you can read more about the design in bug 1431255.

This setup is pretty complex, mostly because of the level of encapsulation needed. The web content must not be able to probe into the DOM inserted, nor interact with the JS directly. The sandboxes are created per-origin as an extra layer of security to ensure isolation among different origins in the same content process.

Now that the first binding is done and the framework is in place, Tim is setting his sights on the rest. There aren’t too many in-content bindings left after this. The most complex ones are the date and time pickers, the marquee tag, and the “click to play” plugin UI. Once we remove the last one that’ll let us remove the in-content XBL implementation which we expect will provide performance, security, and code simplification benefits.

Flexbox performance improvements

One of the main aspects of the UI that we’d like to migrate away from XUL and towards web standards is flexbox. One reason this is important is that it’ll make it easier to use HTML elements in the browser chrome. But the main thing I wanted to talk about here is that it creates a need to greatly improve the performance of CSS flexbox.

Flexbox perf issues affect web content in Firefox - for example Twitter DMs, WhatsApp, and number of other sites. And as Neil noticed in 2015, switching the browser chrome to use CSS flexbox causes large perf regressions. To track this, we added a pref to enable CSS flexbox in the browser chrome which lets us measure the difference between XUL and CSS flexbox with Talos.

In order to improve performance in both these environments (web content, and chrome with CSS flex layout), the layout team has prioritized optimizing flexbox during the second half of this year. Daniel Holbert landed the first major piece of this effort recently in Bug 1490890. This had a massive impact on some DevTools panels that are already using CSS flex, especially the webconsole. As Nicolas Chevobbe noted, one console test case where characters get typed into the input field sped up from ~800ms to ~100ms.

It’s still TBD when it’ll get fast enough to lay out the browser chrome, but each step in that direction will make websites using flexbox faster in Firefox. Keep an eye on the main flexbox performance metabug if you want to follow along.

XPCOM support for (chrome) Custom Elements

XBL has a way to wire up XPCOM interfaces with DOM elements. You may have seen this before inside of XBL bindings - for example the browser binding uses implements="nsIObserver, nsIBrowser". This lets the XBL binding provide the implementation for functions on that interface, and lets other code QueryInterface to that interface using the element.

This feature is (obviously) not part of the specification for Custom Elements. But if you look closely at our tree of XBL bindings, you can see that a bunch of them inherit from basecontrol which relies on this feature. That means we’ve been blocked off from migrating most of those bindings to Custom Elements.

We are unblocking this on two fronts:

  1. Adding XPCOM support to chrome Custom Elements. This is done - Neil Deakin landed this feature in bugs 1461742 and 1478372.
  2. Remove individual interfaces when possible. Alex Surkov recently removed nsIDOMXULLabelElement, nsIDOMXULLabeledControlElement, and nsIDOMXULCheckboxElement, for example. This also has some overlap with the work bz did to remove nsIDOMElement and nsIDOMNode a few months back, and we’re hoping to do more of this when it makes sense.

Binding Removals

There are 153 bindings left, compared to 161 from the last update and 300 from the start of the project. Here’s a list of changes:

XUL/XBL Replacement Newsletter 7

This is the seventh edition of the XUL/XBL Replacement Newsletter. Since the last edition, we’ve gotten some tooling improvements, landed an experimental HTML browser window and removed a bunch of listbox code.

Web Components Support in DevTools

As you may have heard, Custom Elements and Shadow DOM are riding the train for 63. The DevTools team has also done a lot of work to make sure we have good tooling for these features.

One of these features that I’d like to mention is called “Show Custom Element definition”. A badge appears next to a Custom Element in the Inspector, and when you click on that it takes you directly to your Custom Element class in the Debugger. This also works in the Browser Toolbox and can be seen on any of the Custom Elements we currently ship in the browser window. For example: search for “moz-input-box” nodes in the Inspector to try it.

This highlights some benefits to using web standard tech within the Firefox frontend. We get to use the same DevTools features that we’re shipping to web devs. And (at least in my experience) Firefox devs are quite likely to give feedback and file bugs on tools, which ends up improving those same features.

Finally, I’d like to point out that coordinating the release of a complex platform feature and tooling to go with it is hard to do. It takes a lot of planning and cooperation between the the DOM and DevTools teams. Thanks to Julian Descottes, Belén Albeza, Emilio Cobos Álvarez, Jim Blandy, and many others for making this happen.


The main browser window is currently a XUL document with (mostly) XUL elements in the DOM. We’d ultimately like to support an HTML document with (mostly) HTML elements in the DOM. That’s a long road, though. One milestone we hope to hit along the way is loading an HTML document with (mostly) XUL elements in the DOM.

Practically, this can be done by loading a browser.xhtml file with the same markup as browser.xul. This will allow us to audit and fix issues affecting top-level HTML windows without rewriting the browser window from scratch. And since we have a large suite of browser tests to track progress against, we can be pretty confident about what’s working and what’s still broken. We’ll be tracking that in the top-level HTML metabug

An experimental version of this has now landed. you can try it out by adding this to your .mozconfig file: mk_add_options 'export MOZ_BROWSER_XHTML=1'. It’s worth calling out some of the changes we made to set thi up, so I’ve split them into two groups below.

First group: burning down XULDocument.webidl so that the browser JS doesn’t rely on XUL-specific APIs. This is now finished - see the webidl file when we started vs now. Here are some notable changes:

  • Migrated all calls of document.persist to Services.xulStore.persist (bug 1476030, firefox-dev post).
  • Removed document.width and document.height from XULDocument (bug 1475305).
  • Moved document.getElementsByAttribute[NS] from XULDocument to ParentNode, so it supports all chrome documents and elements (bug 1475342).
  • Moved popupNode, popupRangeParent, popupRangeOffset, and tooltipNode from XULDocument to Document (bug 1480206).
  • Removed addBroadcastListenerFor and removeBroadcastListenerFor (bug 1482170).

Second group: adapting the frontend to work while running inside of an HTML document. This is ongoing, here are some of the changes so far:

  • Added support for XUL Custom Elements inside of chrome HTML documents (bug 1480465).
  • Rewrote callers of document.createElement in browser JS to document.createXULElement to explicitly construct XUL elements even when the document namespace is HTML (bug 1479050).
  • Updated all references to “browser.xul” to `AppConstants.BROWSER_CHROME_URL, which lets us change the URL in one place (bug 1476333, firefox-dev post).
  • XUL documents drop whitespace when parsing, so we frequently refer to APIs like node.firstChild and assume it’s an element. For that to work in HTML documents callers were rewritten as node.firstElementChild (bug 1479125, firefox-dev post).
  • Stopped using <broadcaster> and <observer> (which only work in XUL documents) in browser.xul (bug 1479908).

Thanks to everyone who’s helped with planning, patches, and reviews so far. In particular I’d like to acknowledge Brendan Dahl and Mossop for pushing this forward.

Listbox Removal

We don’t have any <listbox> elements in Firefox anymore. If that sounds surprising, like saying “we don’t have any buttons in Firefox anymore”, there’s a distinction to be made as we still use a lot of lists in the UI.

Previously, there were two main widgets to choose from when rendering a list in chrome: <listbox> and <richlistbox>. Richlistbox is more powerful and more “webby”, and over the course of time most of the UI was updated to use it. Listbox relied on custom layout code to guarantee that the height of a list was a multiple of the height of a row, and handle scrolling differently. This can be useful, but it just wasn’t required for the remaining consumers.

Since only a few <listbox> elements were left, it was a pretty easy decision to remove it and unify on a single list widget. Being able to support just richlistbox lets us focus effort on it and makes it easier to decide what to use when adding new UI. It also allowed us to delete around 3K lines of platform code and 2K lines of frontend code.

Finally, it’s worth mentioning that the <tree> element is implemented similarly to <listbox>, but with more features. This element is on our radar for replacement in the coming year, but it will be more work because we have many instances of trees in Firefox and those UIs are more complex and performance sensitive than listboxes.

Binding Removals

There are 161 bindings left, compared to 176 from the last update and 300 from the start of the project. Here’s a list of changes:

XUL/XBL Replacement Newsletter 6

This is the sixth edition of the XUL/XBL Replacement Newsletter. A quick note before starting: in addition to the ongoing XBL work, there’s been notable progress on other XUL projects. All of this work is interrelated enough that I think it makes sense to talk about it together, so I’ve updated the title to reflect that.

Since the last update we’ve shipped the first few Custom Elements in browser chrome, added better support for top-level HTML documents, and taken a decision on how to handle XBL stylesheets.

Custom Elements

I’m happy to say that we’ve now shipped the first Custom Elements in browser chrome, which is the culmination of a lot of effort from the XBL and DOM teams. So, how does it work? Whenever a new chrome document gets created in the main process, we load a script called customElements.js which defines a base JS class (MozXULElement) and ultimately calls customElements.define for each element that we’ve implemented.

We are using normal web-exposed Custom Element APIs, with two chrome-only additions:

  1. We added a new setElementCreationCallback function, so we can wait to load scripts until the specified tag name is encountered. This will be especially important for elements that aren’t created in the startup path and take some time to load and parse (for instance, the findbar).
  2. The Custom Element spec only allows one element per tag name for “autonomous” elements, although it does allow customizing a few built-in elements. After discussing how to deal with tags that have multiple XBL bindings attached, we realized we needed more flexibility to ease migration and avoid rewriting major parts of the frontend. So we ported the “customized built-in” capability to XUL, while treating every XUL tag name as a “built-in”. This allows us to have different Custom Elements defined for <textbox>, <textbox is="number"> and <textbox is="search">, for example.

Top Level HTML Support

When you open the Browser Console window, it now directly loads an HTML document. We used to first open a XUL wrapper document that would iframe the HTML document in order to support things like like window management, context menus, and tooltips. These features are now supported directly in top-level chrome HTML documents. This work is being continued in order to support the main browser window as HTML, and can be tracked in this metabug.

XBL stylesheets

As Paolo explains in the XBL Replacement Newsletter Special Edition, we’ve taken a decision on how to migrate XBL stylesheets to standard document sheets. This will likely be spread out over two releases to give us time to fix any resulting regressions. The first set of work has landed, changing the sheets that were previously migrated as UA sheets to document sheets in widgets.css.


There are 176 bindings left, compared to 196 from the last update and 300 from the start of the project. Here’s a list of changes:

XBL Replacement Newsletter 5

This is the fifth edition of the XBL Replacement Newsletter. Since the last update we’ve moved below 200 bindings, so we’ve removed just over one third of the bindings. We’ve also been making progress on in-content bindings and doing some cleanup that’s been enabled by the work so far. The easiest way to follow along with this work is to watch the main meta bug.

In Content XBL

Stopping use of XBL in the content process will be a big milestone for the project, and it’ll let us remove a lot of complexity that exists to make these elements secure. We’ve come up with an outline for how to replace in-content bindings that require DOM/JS in the content process: the basic idea is to use a “User Agent” Shadow DOM that’s only accessible to chrome code and to run the JS in a new limited privileged scope. You can see a more detailed proposal on the bug.

In addition to this, we’ve been making progress on removing and simplifying the current in-content bindings:

  • We no longer use XBL for scrollbars! Tim removed the scrollbar binding, and we instead build up native anonymous content to render them. This unblocks further improvements such as using a single element instead of a full DOM tree for scrollbars.
  • The “resizer” is the little grippy icon that shows up on the corner of textareas to let you resize them. Tim removed the resizer binding and we now use native anonymous content instead.
  • touchControls and suppressChangeEvent were separate bindings for mobile that extended the videocontrols binding. Tim removed them and now we now share a single binding with different styling for mobile.
  • XML pretty printing used to require JS to expand and collapse tags. Ian Moody changed this by rendering the tree with HTML <details> and <summary> tags instead. We still use a XBL binding to mount the content into the page, but there’s a bug on file to stop doing that.


  • There was a feature called NODE_FORCE_XBL_BINDINGS that would eagerly attach XBL to a cloned node even before it was added to the DOM. We no longer rely on that feature, so it was removed.
  • We no longer load xul.css in content documents. This used to get loaded when we rendered touchControls, among other things. We still load minimal-xul.css in all content documents, but there’s a new metabug tracking removal of in-content xul to ratchet this down.
  • We’ve been removing nsIDOMXUL* stuff, which also aligns with :bz’s work to remove nsIDOM* stuff. We removed nsIDOMXULTreeElement, nsIDOMXULTextBoxElement, and everything but one attribute from nsIDOMXULCheckboxElement.
  • Neil simplified the XBL implementation of popups by allowing nsXULElement to be subclassed and then using a subclass for menupopup, popup, panel, and tooltip elements.
  • There have been some nice cleanups to the gBrowser object since migrating away from XBL. Dão did a bunch of refactoring, which can be seen in bugs inside the ‘Blocks’ field of the JS migration bug. We also saw a tabpaint perf win when deleting the tabbrowser binding.

Binding Removals

There are 196 more bindings left, compared to 215 from the last update and 300 from the start of the project. Here’s a list of changes:

XBL Replacement Newsletter 4

This is the fourth edition of the XBL Replacement Newsletter. Since the last update we’ve continued to remove bindings and have been making progress on accessibility, autocomplete widgets, and migrating XBL to JS. The easiest way to follow along with this work is to watch the main meta bug.

Accessibility No Longer Relies on XBL

We moved all of the remaining [role] attributes out of XBL and into the accessibility platform code. This work can be seen in Bug 1428930 and blockers. This is a big milestone since we will now be able to migrate any binding to a Custom Element and maintain accessibility. Also, we were able to delete the XBL accessibility platform integration and eliminate a few more bindings that were only used to attach roles to elements.

Autocomplete and Trees

We used to have two separate implementations of the “autocomplete” popup, which is used for combo boxes and for text input fields with an attached drop-down. The older implementation was based on the <tree> element, and in the past few years we’ve been replacing more and more of its uses with the new implementation based on the <richlistbox> element, to overcome the styling and layout limitations of <tree>.

It turned out that the separate search bar in the toolbar was the only instance that still depended on the intricacies of the <tree> version, and once that was fixed we could convert all the other autocomplete popups to use the <richlistbox> version, and remove the bindings that implemented a customized <tree> for this use case.

Tabbrowser XBL to JS Migration

Our largest binding (tabbrowser) was translated into a JS class using the converter script plus manual fixups. Thanks to the reviewers in that bug for sticking with it, and to Potch for upgrading his xmlom package to include XML comments. I’m hoping this same approach can apply to other large bindings, like <browser>.

Binding Removals

There are 215 more bindings left, compared to 240 from the last update and 300 from the start of the project. Here are the list of changes: