The Mozilla
Organization
At A Glance
Feedback
Get Involved
Newsgroups
License Terms
Newsbot
Developer Docs
Roadmap
Projects
Ports
Module Owners
Hacking
Get the Source
Build It
Testing
Download
Bugzilla
Bug Writing
Tools
View Source
Tree Status
New Checkins
Submit A Bug
FAQ
Search

XBL - The Extensible Bindings Language

Author: Dave Hyatt
Change History:

  • Jan 12, 2000 - Second Draft
  • Jan 4, 2000 - Initial Draft

Contents:

Introduction

The current Mozilla infrastructure contains a number of recent feature additions, specifically intended to facilitate the design of user interface elements and the processing of events and operations on those elements. To date, this has been undertaken on a sort of "ad hoc" basis, with features being invented, augmented and redesigned only as needed.

These features include anonymous content, the command dispatcher, the controller system, and the configurable key binding system.

The above features have emerged as critical requirements for the Mozilla application. Unfortunately the design of these features has been haphazard at best. The design has also been particularly difficult because it necessarily involves non-standard extensions to CSS, the DOM, and HTML.

The purpose of this document is to provide a concrete proposal for a redesign of the current system in order to enable the full range of functionality we need for the Mozilla application. In the following sections, I will tie together these different features into a new language, XBL, that can exist apart from XUL and that can be used with either XUL or HTML.

The Structure of an XBL Document

An XBL file is a well-formed XML file. The root element of the file is a <bindings> tag. The namespace of XBL is http://www.mozilla.org/xbl.

An XBL file consists of zero or more bindings, each declared as a child of the root element with a <binding> tag.

<bindings xmlns="http://www.mozilla.org/xbl">
  <binding>
    ...
  </binding>
  <binding>
    ...
  </binding>
  ...
</bindings>
                  

CSS and XBL

An element in XML (in particular XUL and HTML elements) can point to a specific binding in an XBL file. The location of this file is specifiable using CSS. A new property, behavior, can be used.

textarea {
  behavior: url("chrome://global/content/htmlBindings.xml#textarea");
}
                  

Bindings are identified using a name attribute. In the CSS, the # notation is used to reference a specific binding within the XBL file. If a binding name is not specified, then the first binding defined in the XBL file is used.

The binding found in the XBL file will be applied to any elements that match the style rule. In the above example, a binding is referenced that will apply to all HTML textarea elements.

Note: There is currently a working draft afoot for adding behavioral extensions to CSS. This proposal complements that draft through its support of the behavior property. XBL is one particular behavioral implementation that CSS can reference. Another proposed implementation of behaviors is HTC (HTML Components). This implementation, however, is not generalizable to other namespaces, is not well-formed XML, and does not support the extra anonymous content capabilities that XBL offers.

The <binding> Element

The binding element is used to dynamically bind new information to another XML element (e.g., a XUL or HTML element). Each binding has three components.

 

  1. Content. A binding can specify new content that is placed underneath the bound element. This content can either be anonymous (hidden from the bound element) or explicit (visible to the bound element). This doesn't have to be implemented in the 5.0 timeframe.

     

  2. Methods & Properties. A binding can specify additional methods that can be invoked on the element. It can also specify additional properties that can be retrieved or set on the element. In this way the functionality of the bound element becomes extensible. This doesn't have to be implemented in the 5.0 timeframe.

     

  3. Behavior. A binding can specify event handlers for specific actions like key and mouse events that can make use of the new functionality applied in the binding.

The following sections cover each component of a binding in more detail.

The <content> Element

The content element is used as a child of the binding element to indicate additional content that can potentially be built underneath the bound element. A binding can have only one content element as a child.

This content is anonymous and does not alter the bound element's document object model. The content itself is declared normally, just as it would appear if it were really declared underneath the bound element.

Example: Scrollbars frequently differ from platform to platform. On the Windows operating system a scrollbar can be implemented using an up button, a scrollbar thumb, and a down button. On the BeOS, however, a scrollbar consists of a pair of up/down buttons, a scrollbar thumb, and a second pair of up/down buttons.

By making the scrollbar's content anonymous, and by moving the anonymous content itself into an XBL file, CSS can then be used to point to two different XBL files on the different operating systems.

 

<bindings xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          xmlns="http://www.mozilla.org/xbl">
  <binding>
    <content>
      <xul:titledbutton class="upButton" oncommand="parentNode.lineUp();"/>
      <xul:thumb class="thumb" .../>
      <xul:titledbutton class="downButton" oncommand="parentNode.lineDown();"/>
    </content>
    ...
  </binding>
  ...
</bindings>
                  

Anonymous Content and the DOM

Although anonymous content is not really contained in the document, it can be styled by style sheets loaded by the document. As far as style resolution is concerned, the anonymous content can be referenced as if it is contained in the document. Scripts on anonymous content can also reference JavaScript variables and functions defined within the global script object that corresponds to the document.

The formatting objects constructed from anonymous content are placed on the end of the containing object's list of children. In other words, if explicit content and anonymous content are both specified for a bound element, then the explicit content's formatting objects appear first in the flow (with all the usual exceptions for absolutely positioned, fixed positioned, floaters, etc.).

Events that occur on anonymous content are not visible to the bound element or to its document. Within the anonymous content tree itself, events bubble normally and are also capturable by other anonymous content.

It is possible for anonymous content to be bound to another XBL file that can itself contain anonymous content. In this case, the nested anonymous content is invisible to the outer anonymous content. This nesting can be taken to an arbitrary level.

Example: The scrollbar thumb itself can be implemented using two springs and a titledbutton. This content could be defined in an XBL file bound to the thumb element. It is invisible to the thumb that it is bound to, and in turn the thumb is invisible to the scrollbar that it is bound to.

Exclusionary Construction of Content

By default, content is only built if the bound element has no child content already. In certain situations, however, it is desirable to build anonymous content even when the element already has children. The excludes attribute can be used in this case. Its value is a comma-separated list of child tags that should be ignored during the check regarding whether or not anonymous content should be constructed.

Example:: The menu element in XUL can contain template or observes elements as children. It can also contain a menupopup element as a child. If, however, no content is specified other than those three children, then the contents of the menu must still be constructed anonymously.

 

<bindings xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          xmlns="http://www.mozilla.org/xbl">
  <binding>
    <content excludes="template,observes,menupopup">
      <xul:titledbutton class="menu-left"/>
      <xul:titledbutton class="menu-text"/>
      <xul:spring flex="1" class="menu-spring"/>
      <xul:titledbutton class="menu-accel"/>
      <xul:titledbutton class="menu-right"/>
    </content>
    ...
  </binding>
  ...
</bindings>
                  

Inheritance of Attributes

In some cases attributes that are set or changed on the bound element should be reflected into the binding's content. The inherits attribute can be used on specific elements within the content binding. This attribute is a global attribute, and therefore its namespace must be explicitly qualified as XBL. The value of the attribute is a comma-separated list of attributes that should inherit from the bound element. These attributes always remain in sync with the bound element; if the attribute's value changes on the bound element, then the anonymous content is also updated to reflect the new value.

In some cases the attribute on the bound element is not the same as the attribute on the anonymous content that should be set. In this case, a colon-separated pair can be specified in the inherits attribute. The first attribute in the pair is mapped to the second attribute in the pair.

Example:: The menu element in XUL supports the value attribute as a means of specifying the menu item's text. It also supports the acceltext attribute as a means of specifying the accelerator text for a menu item. Because titledbutton elements are used for both, the value attribute must be specified on both. The menu text button can inherit the value from the bound element. The menu accelerator button must inherit from acceltext and map that attribute to its value attribute.

 

<xbl:bindings xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
              xmlns:xbl="http://www.mozilla.org/xbl">
  <xbl:binding>
    <xbl:content excludes="template,observes,menupopup">
      <xul:titledbutton class="menu-left"/>
      <xul:titledbutton class="menu-text" xbl:inherits="value"/>
      <xul:spring flex="1" class="menu-spring"/>
      <xul:titledbutton class="menu-accel" 
                        xbl:inherits="acceltext:value"/>
      <xul:titledbutton class="menu-right"/>
    </xbl:content>
    ...
  </xbl:binding>
  ...
</xbl:bindings>
                  

The <children> Element

XBL can be used to interpose anonymous content in between the bound element and its explicit children. This has no effect on the bound element's document object model. Instead, the formatting objects created from the anonymous content are constructed as immediate children of the bound element's formatting object. The formatting objects that are built from the explicit child content of the bound element are inserted underneath the anonymous formatting objects at a location specified in the XBL.

The children tag within anonymous content specifies the place at which to insert the explicit children of the parent within the formatting object tree. When styling these children, the anonymous content nodes are visible, just as if they existed in the document itself.

Events that originate on explicit child content will bubble through their parent anonymous content elements before reaching the bound element. In effect, the event begins in the bound element's DOM, bubbles through the parent anonymous content, and then bubbles up to the bound element. Capturing works in a similar fashion.

Example:: In XUL a <scrollgroup> tag can be used to specify a scrollable window. Its explicit children are placed inside a scrollport object, and a scrollbar is built as a sibling of the scrollport in the formatting object tree. This extra scrollport frame need not be defined by the user, but its presence is required in order for the scrollable window to work properly.

In this example, an XBL binding for the scrollgroup is made that ensures that any of the scrollgroup's explicit children are placed inside the scrollport so that they can be scrolled.

<xbl:bindings xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
              xmlns:xbl="http://www.mozilla.org/xbl">
  <xbl:binding>
    <xbl:content excludes="template,observes,menupopup">
      <xul:scrollport>
        <xbl:children/>
      </xul:scrollport> 
      <xul:scrollbar class="vertical"/>
    </xbl:content>
    ...
  </xbl:binding>
  ...
</xbl:bindings>
                  

The <interface> Element

The interface element is used to specify additional functions that can be invoked on the bound element, as well as additional properties that can be set or retrieved on the bound element. A binding element can have only one interface element child.

Methods

An interface element defines zero or more methods and zero or more properties. Each method is specified using the method tag, and each property is specified using the property tag. The name attribute can be used on either of these two elements to indicate the name of the method or property that will be added to the bound element.

Example: A scrollbar element in XUL can have methods defined on it using XBL that allow for scrolling up and down, either by a line or by a page. It can also have a property that represents the current index of the scrollbar.

 

<bindings xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          xmlns="http://www.mozilla.org/xbl">
  <binding>
    <content>
      <xul:titledbutton class="upButton" oncommand="parentNode.lineUp();"/>
      <xul:thumb class="thumb" .../>
      <xul:titledbutton class="downButton" oncommand="parentNode.lineDown();"/>
    </content>
    <interface>
      <method name="lineUp">
        ...
      </method>
      <method name="lineDown">
        ...
      </method>
      <property name="currentIndex"/>
    </interface>
  </binding>
  ...
</bindings>
                  

Method and property names are case-sensitive. The convention to use in Mozilla: the first letter of method and property names should always be lowercase (just as with JavaScript methods and properties).

Parameters

Arguments to methods can be specified using the <argument> tag. The argument tag can also take a name attribute. In the implementation of the function the value of this attribute can be used to refer to a variable that is bound to the value of the argument passed in to the method.

The type of an argument can be specified using the type attribute, although this is not required. Method arguments in XBL can be of polymorphic type, assuming the scripting language used by the implementation supports it.

Example: A scrollbar can define a scrollTo method that requires a single argument, a number indicating the line to scroll to.

 

<bindings xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          xmlns="http://www.mozilla.org/xbl">
  <binding>
    ...
    <interface>
      <method name="scrollTo">
        <argument name="index"/>
        ...
      </method>
      ...
    </interface>
    ...
  </binding>
  ...
</bindings>
                  

The return type of a method can be specified on the method tag using a returns attribute. Just as with argument types, this value need not be specified if the underlying scripting language supports polymorphic return types.

Method Implementations

The body tag is used to specify the implementation of a particular function. It contains a script that is executed when the method is invoked. The type attribute can be used to specify the language of the script.

Example: The scrollbar defines an implementation for the scrollTo method.

 

<bindings xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          xmlns="http://www.mozilla.org/xbl">
  <binding>
    ...
    <interface>
      <method name="scrollTo">
        <argument name="index"/>
        <body>
          <![CDATA[
          if (index == currentIndex) return; ...
          ]]>
        </body>
      </method>
      ...
    </interface>
    ...
  </binding>
  ...
</bindings>
                  

The method body is evaluated in the context of the bound element. Thus properties of the element can be referred to by name (as is done for the currentIndex property in the example above).

Properties

The property tag is used to specify a property in XBL. By default the property can be set or retrieved on the element. The name attribute is used to specify the name of the property.

The readonly attribute if present and set to true indicates that the property can be inspected on the bound element but not changed.

The value attribute on the property element is a script that evaluates to an initial value for the property.

Example: The scrollbar initializes its current index to 0.

 

<bindings xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          xmlns="http://www.mozilla.org/xbl">
  <binding>
    ...
    <interface>
      ...
      <property name="currentIndex" value="0"/>
      ...
    </interface>
    ...
  </binding>
  ...
</bindings>
                  

Interfaces and XPCOM

An interface element can point to an XPCOM interface and to a specific implementation of that interface. When this is done, no methods or properties are specified in the XBL. Instead they are picked up from the XPIDL description that corresponds to the XPCOM interface.

[Note: Only interfaces that have had XPT files generated for their descriptions can be used with XBL.]

The name attribute can be used to point to a symbolic name for the interface. When this is done, the interface is retrieved from the interfaces object that is accessible from the Components object. The iid attribute can be used to point directly to a specific interface ID.

Implementations can be referred to using the progid attribute, which refers to a progid, or a specific implementation can be directly referred to using the classid attribute.

It is permissible to specify an XPCOM interface and to define the implementation inline using <method> and <property> tags. Note that it is not permissible to point to an XPCOM implementation without also specifying either an interface name or an IID.

<bindings xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          xmlns="http://www.mozilla.org/xbl">
  <binding>
    ...
    <interface name="nsIController" progid="component://netscape/editor/controller"/>
    ...
  </binding>
  ...
</bindings>
                  

The <handlers> Element

The final component of a binding is the <handlers> element. This element is used to define new event handlers that should be invoked when events occur on the element. The handlers element contains zero or more handler elements as children. Each element corresponds to a single event handler that will be invoked when the handler is matched to the event.

Handler Elements

The type attribute specifies the type of event that the handler wishes to field. Its name must corresponds to an event name, such as click or keypress. A comma-separated list of event names can be given if, for example, the handler should fire on more than one action, e.g., when the return key is pressed or when the mouse is clicked.

The button attribute can be used to restrict a mouse event to a specific button. It has values of left, middle or right.

There are several modifier keys supported. They each have separate attributes. If set, then on a mouse or key event, these modifier keys must be down for the event to fire. The value of a modifier key attribute is true if the modifier key must be down. The modifier key attributes include shift, control, alt, command, and meta.

The key attribute can be used to stipulate that on a key event the key must be the primary key used. The keycode attribute works in a similar fashion, but it allows for the selection of unusual keys like space or home. The virtual key codes can be found in the Mozilla source. Note: Include link to Mozilla source file.

The capturer attribute, if set to true, indicates that the event should only fire during the capturing stage of DOM event flow.

The value attribute contains the event handler script that should be invoked when the event element is matched.

Example: A list box in HTML moves the selection up and down when the appropriate arrow keys are pressed. XBL event elements can be used to install this behavior on a list box.

 

<bindings xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          xmlns="http://www.mozilla.org/xbl">
  <binding>
    ...
    <handlers>
      ...
      <handler type="keypress" keycode="vk_up" 
                  value="moveDown()"/>
      <handler type="keypress" keycode="vk_down"
                  value="moveUp()"/>
      ...
    </handlers>
    ...
  </binding>
  ...
</bindings>
                  

Event Redirection

A handler element can be used to map one event to another event. When this happens, a new event is synthesized from the old event and fired into the DOM. The <mapto> element is used to perform the redirection. It is a child of the handler element, and it can have all the attributes that an handler element can. These attributes specify the values of the new event and provide information regarding how the fields of the event object should be filled in.

The new event fires on the bound element and moves through the capturing and bubbling stages just as the old event does. An event element that redirects can still have a value attribute specified. This code executes prior to the firing of the new event. This can be useful in cases where it is desirable to prevent the continued processing of the old event.

 

Extensibility of Events

Events are extensible, and code can be used to invoke events with arbitrary names. Handlers can be defined to deal with any new events. For example, a new event called close could be fired when a window in XUL wishes to close itself up.

Example: Dialog boxes attempt to close when the ESC key is pressed. An XBL file bound to all dialog windows can be used to ensure that the ESC key causes a close handler to fire.

 

<bindings xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          xmlns="http://www.mozilla.org/xbl">
  <binding>
    ...
    <events>
      ...
      <event type="keypress" keycode="vk_escape">
        <mapto type="close"/>
      </event>
      ...
    </events>
    ...
  </binding>
  ...
</bindings>
                  

This mapping capability coupled with extensibility of events is quite powerful. It can be used to perform key remapping. For example a Dvorak keyboard layout could be implemented within Mozilla by supplying a set of redirects on the outermost XUL window.

Other examples of event redirection include platform-specific bindings. For example, CONTROL+click on the Mac could be remapped to a right mouse button click. Finally modifier keys can be mapped to other modifier keys, thus allowing for platforms to choose modifier keys as appropriate for specific bindings.

Binding Inheritance

A binding can inherit from another binding. When this inheritance is specified, the binding picks up all the content and event handlers defined in the base binding, and it picks up the additional methods and properties defined in the base binding.

The Extends Attribute

The extends attribute is used to specify the URL of the base class binding. The URL is just like the one specified in the behavior CSS property; the # notation can be used to point to a specific binding, either in the same file or in another file all together.

Inheritance can be taken to an arbitrary level, i.e., binding A can inherit from binding B, which in turn inherits from binding C. Only single inheritance is allowed.

This feature allows bindings to be reused by different elements that also wish to define additional bindings of their own. Most importantly, it can be used in conjunction with chrome URLs to include platform-specific event redirects and bindings unique to a given operating system.

Example: By default, input text fields have a certain set of bindings defined for simple navigation. An autocompleting text field, e.g., the URL bar in a browser window, wishes to inherit all of the default behavior, but also to add support for auto-completion. It can do this by inheriting from the base binding.

 

<bindings xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
          xmlns="http://www.mozilla.org/xbl">
  <binding name="autoCompleteBinding"
           extends="resource:/chrome/htmlBindings#inputTextField">
    ...
  </binding>
  ...
</bindings>
                  

Inheritance of Content

By default when one binding inherits from another, the content specified by both bindings is built. The derived binding has its content built first, and then the base binding has its content built. Content is always appended to the end of the bound element's formatting object list, so the derived class content shows up first in the flow.

Only one insertion point for explicit content can be specified. If a base class attempts to redefine this insertion point using the children tag, the tag should be ignored.

A derived binding can prevent a base binding's content from being built by placing an inherits attribute on the content element with a value of false.

Inheritance of Methods and Properties

Methods and properties defined in bindings are invoked by making those calls directly on the bound element itself. For example, if a binding defines a doCommand function for a XUL tree widget, then the function can be invoked directly from the tree element.

 

Methods

For methods, the IDL for the DOM element is first checked. If there is no match, then the bindings are searched in order (from derived bindings up to the root binding) for any methods that match the invoked method. Note that it is possible for multiple bindings to have matching methods. When this occurs, only the derived binding's method is called. The base binding's method can be invoked in script by the derived binding using the base keyword followed by the method name, e.g., base.doCommand("delete").

 

Properties

When a property is inspected, the element itself is checked first. If the property is not found, then the bindings are searched in order, from derived binding up to the root binding. The first binding that provides a match is used to obtain the current value of the property.

When a new property is set on the element, the element is checked first. If the property does not currently exist on the element, then the bindings are searched in order. The first binding that has the property defined gets the property set. If no bindings match, then the property is set on the element and not on any of the bindings.

There is no notion of "shadowing" of properties. Only one binding is responsible for the value of a property at any given time. It is not possible for the property to be defined in more than one binding in the same inheritance chain.

Inheritance of Handlers

If a derived binding and base binding both define handlers for the same event, the derived binding's handler is invoked first. This is true both in the bubbling or capturing phases of event handling.

If preventBubble is called on the event during the bubbling phase, then the base binding's event handler will not fire. Similarly, if preventCapture is called on the event during the capturing phase, then a base binding's capturing handler also will not fire. These methods can be used to selectively prevent an event from being fielded by a base class binding.

Rule-Based Construction (Examples)

Sometimes different types of content should be constructed based on the attributes found on the bound element. XBL supports this capability through the usage of inheritance and style rules. If the content varies in this way, then multiple derived bindings can be defined that all inherit from the same base binding.

Example:: A treecell in XUL constructs different anonymous content if an indent attribute is set to true on the cell. In one case, a <treeindentation> element needs to be inserted into the cell. Otherwise it doesn't.

 

<xbl:bindings xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
              xmlns:xbl="http://www.mozilla.org/xbl">
  <xbl:binding name="normalcells">
    <xbl:content excludes="template,observes">
      <xul:titledbutton class="tree-icon" flex="1" xbl:inherits="value,src">
    </xbl:content>
    ...
  </xbl:binding>
  ...
  <xbl:binding name="indentedcells" extends="#normalcells">
    <content>
      <xul:treeindentation>
    </content>
    ...
  </xbl:binding>
  ...
</xbl:bindings>
                  


Contact us at xptoolkitstaff@netscape.com. Want to complain about the new documentation? Email Dave Hyatt.

Copyright © 1998-2000 The Mozilla Organization.
Last modified January 31, 2000.