Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Browser extensions using XUL, Part 1: Create a Firefox browser extension with user-interface features

Uche Ogbuji (uche@ogbuji.net), Partner, Zepheira, LLC
Uche photo
Uche Ogbuji is Partner at Zepheira, LLC, a solutions firm specializing in the next generation of Web technologies. Mr. Ogbuji is lead developer of 4Suite, an open source platform for XML, RDF and knowledge-management applications and lead developer of the Versa RDF query language. He is a Computer Engineer and writer born in Nigeria, living and working in Boulder, Colorado, USA. You can find more about Mr. Ogbuji at his Weblog Copia.

Summary:  Create extensions that go beyond the built-in capabilities of Web browsers. The Mozilla project's XUL engine is a user-interface language that you can use to extend Mozilla browsers, or to build stand-alone applications. XUL is a surprisingly easy way to build cross-platform browser extensions, and this pair of articles demonstrates how.

View more content in this series

Date:  02 Oct 2007
Level:  Intermediate
Also available in:   Chinese  Japanese

Activity:  39762 views
Comments:  

The Mozilla project team very early decided that it would standardize core development in C++, but that it would create a component system, XPCOM (Cross Platform Component Object Model), for sharing core and extension functionality across platforms. It also developed a means of designing user interfaces for such components in a platform-neutral language it called XUL (XML User Interface Language), pronounced "zool". Not much is special about the use of XML in XUL: The team could have come up with a completely new syntax, and it's best to think of XUL as just another programming language that happens to use XML for basic syntax. XUL does take advantage of existing Web technologies such as ECMAcript (most popularly known in its JavaScript implementation), DOM, and CSS, so it should be fairly easy for Web developers to learn. A companion language, XBL (eXtensible Bindings Language), is used to control dynamic behavior of XUL elements. XUL and XBL are powerful enough to develop a full browser or other full, cross-platform applications based on Mozilla components, but for most developers XUL is used more modestly to extend or manipulate the user interface of an existing browser or other application (a use case for which XUL was carefully designed). This is most often the case when you are developing a browser extension, and the most attractive target for most Mozilla browser extensions is Firefox, Mozilla's very popular stand-alone browser. Firefox is built in XUL and JavaScript. It is a demonstration of the power of XUL, but it is also very open for extension using XUL.

This article puts together the basic pieces you'll need to create most extensions with user-interface features—XUL, CSS, JavaScript, and DOM. It isn't an introduction to XUL—you can find some such introductions linked in Resources. It assumes you understand the basic concepts of the language and focuses on showing you how to put it to work. It also assumes basic knowledge of JavaScript, DOM, and CSS.

XUL the direct way

One of the great things about XUL is that Mozilla browsers treat it, for the most part, like any other Web content. This means you can rapidly try things out and deploy things during the development phase, before worrying about proper packaging into applications or full extensions. Several useful tools are available for such rapid deployment—Ted Mielczarek's Extension Developer's Extension (see Resources) includes many useful tools such as the Live XUL Editor which allows you to edit and preview XUL online. He also offers a very simple XUL page on his Web site that allows you to do much the same (barring some security restrictions applied to all XUL loaded over the Web). For the most part, I prefer a more direct approach to the XUL development cycle: editing in a good text editor, especially one that provides features to ease some of the pain of authoring XML, and then I simply load the XUL file directly into a Firefox tab. I edit again to make any tweaks or fixes, and reload the page for that file. Listing 1 (stats.xul) is a simple XUL example that demonstrates some of the language's power. It allows you to enter a URL and view the resulting Web page in one panel and some simple statistics about the page in another.


Listing 1 (stats.xul). Simple XUL example
                <?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
        id="statswindow" title="View Web page stats">
  <vbox flex="1">
    <hbox id="toppanel">
      <label value="Enter a URL:"/>
      <textbox id="url" flex="1" value="http://www.ibm.com/developerworks/web"/>
      <button label="Go!"/>
    </hbox>
    <description value="Current page:"/>
    <hbox flex="1">
      <iframe id="contentview" src="http://www.ibm.com/developerworks/web" flex="2"/>
      <vbox>
        <groupbox>
          <caption label="Stats"/>
          <grid flex="1">
            <columns>
              <column flex="1"/>
              <column flex="1"/>
            </columns>
            <rows>
              <row>
                <label value="Word count"/>
                <textbox class="count" id="wordcount" value="N/A" readonly="true"/>
              </row>
              <row>
                <label value="Character count"/>
                <textbox class="count" id="charcount" value="N/A" readonly="true"/>
              </row>
              <row>
                <label value="Element count"/>
                <textbox class="count" id="elemcount" value="N/A" readonly="true"/>
              </row>
            </rows>
          </grid>
        </groupbox>
        <spacer flex="1"/>
      </vbox>
    </hbox>
  </vbox>
</window>

    

The chrome://global/skin/ stylesheet declaration makes the browser use the default global.css from your chrome package, representing either the built-in Firefox look and feel or some variation if you have a skin installed. The window uses a set of nested boxes to organize content, but I try to avoid too much fiddling with presentation (I'll get to that in the next section) and stick mostly to the logical grouping of UI elements. The iframe element, which is similar to the HTML element of the same name, creates a content frame into which the Web page of interest is rendered, defaulting to http://www.ibm.com/developerworks/web, which is also the value placed in the url textbox. These values are just matched so the default view makes sense to the user and have nothing connecting them just yet (I'll get to that in the later section). A groupbox comes in handy for organizing the stats entries, each of which is a read-only text box defaulting to a dummy value for now. The result is a simple, static window that, thanks to the power of iframe, still offers an impressive result. Save it in a file "stats.xul" and load this into any Mozilla browser window. You can use a "file:" URL, or the "Open File" menu in Firefox. You should get a display similar to figure 1.


Figure 1. Firefox browser window with Listing 1 loaded
Listing 1 viewed in Firefox browser

Adding presentation style

You can do some manipulation of positioning of UI elements in XUL, but for the most part the fine details of how a window looks are a matter of style that is better left to a stylesheet. Using CSS for XUL allows you to control the usual properties—colors, fonts, spacing, and sizing—familiar from CSS for HTML or other XML. Listing 2 (stats.css) shows some declarations for tweaking the presentation of Listing 1.


Listing 2 (stats.css). CSS to be applied to Listing 1
                window {
  font-family: arial, "lucida console", sans-serif;
}

description {
  padding: 5px;
  color: blue;
}

#toppanel {
  padding: 5px;
}

#contentview {
  padding: 5px;
  border: thin solid black;
}

.count {
  width: 5em;
}

    

You can see the rules using ID, class, and element selectors matching parts of Listing 1. You can apply this stylesheet by adding an additional declaration at the top of the XUL file, as in Listing 3, which only shows the first four lines of the file after updating to add the new CSS declaration.


Listing 3. Updated first few lines of Listing 1 with added stylesheet declaration
                <?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="stats.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"

    

Notice that I didn't remove the declaration for chrome://global/skin/. You almost always want to do the same, and the browser will combine the global skin with your more specific stylesheet. Figure 2 shows the updated XUL window with a stylesheet, loaded into Firefox.


Figure 2. Firefox browser with XUL window using CSS
Firefox browser with XUL window using CSS

Bringing things to life with script

The last step in developing this demo XUL application is to make the controls work. We do this by binding the control elements to behavior. XUL has a sister language, XBL, which allows you to perform much of this binding using declarations, reducing the amount of required script. But in this article the binding will be through event attributes that reference JavaScript functions.


Listing 4 (stats-styled-scripted.xul). Listing 1 updated with CSS and script declarations, as well as script hook attributes
                <?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="stats.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
        id="statswindow" title="View Web page stats">
  <script type="application/x-javascript" src="stats.js"/>
  <vbox flex="1">
    <hbox>
      <label value="Enter a URL:"/>
      <textbox id="url" flex="1" value="http://www.ibm.com/developerworks/web"/>
      <button label="Go!" oncommand="change_url(event)"/>
    </hbox>
    <description value="Current page:"/>
    <hbox flex="1">
      <iframe id="contentview" src="http://www.ibm.com/developerworks/web" flex="2"/>
      <vbox>
        <groupbox>
          <caption label="Stats"/>
          <grid flex="1">
            <columns>
              <column flex="1"/>
              <column flex="1"/>
            </columns>
            <rows>
              <row>
                <label value="Word count"/>
                <textbox class="count" id="wordcount" value="N/A" readonly="true"/>
              </row>
              <row>
                <label value="Character count"/>
                <textbox class="count" id="charcount" value="N/A" readonly="true"/>
              </row>
              <row>
                <label value="Element count"/>
                <textbox class="count" id="elemcount" value="N/A" readonly="true"/>
              </row>
            </rows>
          </grid>
        </groupbox>
        <spacer flex="1"/>
      </vbox>
    </hbox>
  </vbox>
</window>
    

Notice the added script element within window, and the added attribute on the "Go!" button— oncommand="change_url(event)". Listing 5 is the referenced JavaScript file "stats.js".


Listing 5 (stats.js). JavaScript code to handle "Go!" button
                //Invoked in response to a click on the "Go!" button
function change_url(event)
{
    //Variables for convenient access to specific elements in the XUL
    var urlbox = document.getElementById("url");
    var contentview = document.getElementById("contentview");
    var wordcountbox = document.getElementById("wordcount");
    var charcountbox = document.getElementById("charcount");
    var elemcountbox = document.getElementById("elemcount");

    //Setting this attribute, happens to change the visible contents of the panel
    contentview.setAttribute("src", urlbox.value);

    //Fake up the update code for now, to allow running in Firefox
    wordcountbox.previousSibling.value += " (fake)";
    wordcountbox.value = "1000";
    charcountbox.previousSibling.value += " (fake)";
    charcountbox.value = "100";
    elemcountbox.previousSibling.value += " (fake)";
    elemcountbox.value = "10";
}

    

Listing 4 binds the function change_url to a click of the "Go!" button. This function receives the event details for the click, though they are not used in this case. The global document object allows you to use DOM to access the various XUL elements, in this case by using getElementById to find an element by its unique ID. XUL elements of course have XML attributes, but they also have object properties, and sometimes even though attributes and properties have similar names, they behave differently when queried or manipulated. For example, I get the text within the URL text box using code such as urlbox.value rather than urlbox.getAttribute("value"). The latter would always read the original content of the text box ("http://www.ibm.com/developerworks/web") regardless of what the user had entered since loading the page. Similarly, if you wanted to update the visible content of such a text box in code, you should write urlbox.value = newvalue rather than urlbox.setAttribute("value", newvalue). You can see this principle in play in the code that updates the count text boxes at the bottom of the function. These nuances are all covered in the XUL reference documentation, so be sure to read carefully about any XUL element you use.

The wall of security

The attribute versus property warning also applies to the line contentview.setAttribute("src", urlbox.value);. The more correct way to go to a new URL would be: contentview.contentDocument.location.href = urlbox.value;. But there is a problem with that line. Firefox's strict security model for XUL documents means that if you try to access some sensitive object attributes, including contentview.contentDocument, your JavaScript will throw an exception. You'd need to use the Error Console window to see the error, which will even then be something vague and generic such as "Error: uncaught exception: Permission denied to create wrapper for object of class UnnamedClass". This is the main problem with the direct means of experimenting with XUL. In the next article I'll show you how to turn the raw materials from this article into a proper Firefox extension, which avoids security limitations through proper chrome registration. For now, the code changes the unrestricted src attribute of contentview (which happens to give a visible result), and makes dummy changes to the count text boxes to show you the basic setup of scripting in XUL.


Wrap up

You've seen how naturally XUL mixes with the basic building blocks of Web development. XUL has a wealth of UI elements and each one has a wealth of attributes and properties, adding up to a generous toolbox for building applications and extensions. Loading XUL directly into the browser is a handy way to rapidly prototype and storyboard XUL applications, but once you start manipulating things with script you may run into unpredictable difficulty. Luckily you have the option of XULRunner, a stand-alone tool created by Mozilla developers. XULRunner can run XUL files outside of any browser, thus avoiding the stringent security model. It's definitely a developer's tool, and can be a pain to get working, especially on some platforms, but it's an important option for developing and deploying XUL projects. In the next article I'll show you how to package the pieces from this one into a Firefox extension, with updates to the script to take advantage of the lowered security barriers.


Resources

Learn

Get products and technologies

Discuss

About the author

Uche photo

Uche Ogbuji is Partner at Zepheira, LLC, a solutions firm specializing in the next generation of Web technologies. Mr. Ogbuji is lead developer of 4Suite, an open source platform for XML, RDF and knowledge-management applications and lead developer of the Versa RDF query language. He is a Computer Engineer and writer born in Nigeria, living and working in Boulder, Colorado, USA. You can find more about Mr. Ogbuji at his Weblog Copia.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=259422
ArticleTitle=Browser extensions using XUL, Part 1: Create a Firefox browser extension with user-interface features
publish-date=10022007
author1-email=uche@ogbuji.net
author1-email-cc=