An Introduction to Firefox Extensions

Abstract

Firefox extensions are useful tools, both to increase your own productivity as a developer and to help make your other projects more accessible to your users. This introduction will walk you through setting up a basic extension, explaining the steps required so you can create your own extensions, whether for business or pleasure.


Introduction

Writing Firefox Extensions can seem like a daunting task. Certainly there are plenty of useful extensions available, from development toolbars, to gmail notifiers, to the sqlite3 extension. However, due to the lack of documentation, it’s easy to feel a bit of vertigo before jumping in to developing one yourself. As we work through this tutorial, you’ll become more familiar with how Firefox extensions are created and developed. By the end of the tutorial, you’ll be comfortable enough to start building extensions on your own.

The basic components of a Firefox extension are CSS, Javascript, and XUL.

What is XUL, you ask? XUL is an extensible user interface language, based on XML. It allows you to define interface components of the Mozilla browser using a structured data language, similar to HTML.

These three components work together to provide complex applications. Logic is all done via Javascript, while interface components are created using XUL, and then styled with CSS. This structure allows you to create relatively complex systems using relatively simple tools.

To begin, create a directory where you can place all of the component files for your extension, and let’s get started!

Laying the Foundation

Every Firefox extension must have an install manifest, or a file called install.rdf at the top-level. This file provides basic information about the extension, such as its version, author, and most importantly, an id. The id is a crucial element, as it distinguishes your extension as unique from any number of extensions a user might install.

So go ahead and create a file called install.rdf in your new directory, then open it up in your favorite text editor.

The install.rdf file is a standard XML document that must follow the standards set by Mozilla, so that the Firefox application can read the information correctly. The Mozilla Developer Center has additional information about optional parameters that can be added to this file, but we’ll focus on the basics.

Copy and paste the following code into your install.rdf file:

<?xml version="1.0"?>

<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:em="http://www.mozilla.org/2004/em-rdf#">
  <Description about="urn:mozilla:install-manifest">
    <!-- more -->
  </Description>
</RDF>

This is the basic structure of all install manifests for any Firefox extension you will find. We load the XML namepaces from W3C and Mozilla, and then define our install manifest.

There are several parameters that we’re required to set in this file. We’ll place the rest of the code in place of the <!-- more --> in our XML file. First of all, we need to set the id, to identify this extension to Firefox. IDs used to be a long formatted string that you had to generate, but now your id needs to be in the format of an email address. For example, extension@mycoolsite.com. This does not have to be a real email address; it’s simply used to identify the extension. In addition, we’ll have to supply the version number, so Firefox knows how to handle future versions of our extension. Let’s go ahead and add the additional code to your install.rdf file, as in this example:

<?xml version="1.0"?>

<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:em="http://www.mozilla.org/2004/em-rdf#">
  <Description about="urn:mozilla:install-manifest">
    <em:id>extension@mycoolsite.com</em:id>
    <em:version>0.0.1</em:version>
  </Description>
</RDF>

Now the id and version for our extension are defined in your install.rdf file. However, there are still some additional values we need to set. The last required properties are type, targetApplication, and name.

The type is a number that Firefox uses to determine whether or not your add-on is an extension, a theme, or something else entirely. Mozilla set the value for Firefox extension to 2, so we’ll use that value.

The targetApplication is a small block that shows what applications the extension with work with (other Mozilla products use the same type of extensions), and the versions it will work with. We’ll use the Firefox ID, and use a minimum version of 1.5, with a maximum version of 3. This will prevent someone from trying to install an old extension that may not be supported by Firefox 4, or other versions in the future.

Finally, the name is simply what you choose to call your extension. Enjoy the freedom of choice! Here’s a sample of what your install.rdf might look like now:

<?xml version="1.0"?>

<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:em="http://www.mozilla.org/2004/em-rdf#">
  <Description about="urn:mozilla:install-manifest">
    <em:id>extension@mycoolsite.com</em:id>
    <em:version>0.0.1</em:version>
    <em:type>2</em:type>
    <em:targetApplication>
      <Description>
        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
        <em:minVersion>1.5</em:minVersion>
        <em:maxVersion>3.0.*</em:maxVersion>
      </Description>
    </em:targetApplication>
    <em:name>My New Extension</em:name>
  </Description>
</RDF>

Sweet Success

Congratulations! You now have a fully functional Firefox extension. Ready to test it out?

Go ahead and grab the contents of your directory – at this point, this should only be the install.rdf file. Create a zip file from those contents. If you’re using OSX or a Linux-based system, you may wish to generate the xpi file using the following terminal command: cd [PATH_TO_EXTENSION_FOLDER] && zip -r ../myfirstextension.xpi *

Windows users can simply select the component files, right-click, and use the built-in menu tools to create a zip file, and then rename the extension to .xpi. However, depending on your setup, you may need to modify your folder options so that file extensions are not hidden.

Important

Be careful not to zip the containing directory, but only the contents inside of it. If the install.rdf ends up in a subdirectory of your zip folder, Firefox will not be able to install the extension.

Got your new XPI file? Open up Firefox and navigate to the directory where the new file resides. Go ahead and click, and Firefox will attempt to install this, just like any plugin you might download directly from the web. Go ahead and continue to install. Firefox will need to restart, and when it does, you’ll notice your brand new extension has been successfully installed! Figure 1, “Firefox Add-On Manager”

Figure 1. Firefox Add-On Manager

Firefox Add-On Manager


You’ll notice that the extension shows up on your list of add-ons, using the name and version number that you specified in the install.rdf file.

While all this is great, it certainly doesn’t change anything about the way Firefox behaves. After all, that’s really what we’re after. Still, at least we know we can install custom extensions this way.

Creating Your First Interface

Let’s change your extension’s name to something a bit more specific. Not a problem, right? You can simply open up the install.rdf file, rezip the contents, uninstall the add-on, reinstall the add-on, restart Firefox, and you’re all set!

Going through this process every time you make a change can get really tedious really quickly. However, the way Firefox is structured actually allows you to modify the extension while it’s installed.

Application Data

Many applications use a specific directory to store information they may need the next time they are run. Firefox stores profile information, along with extensions, within such a folder.

On Windows XP:

C:\Documents and Settings\[USER]\Application Data\Mozilla\Firefox\Profiles On OS X:

~/Library/Application Support/Firefox/Profiles On most linux distributions:

~/.mozilla/firefox Within this directory, you should see one or more profile folders. Inside of the profile folder is an extensions folder.

In here, you’ll find a folder that corresponds to the id you set for your extension, in our case, extension@mycoolsite.com.

If you look inside that folder, you’ll notice that it contains the same install.rdf file that we created earlier. In fact, all Firefox really does is unzip the extension into that new folder. You may also see a file called chrome.manifest. This is an additional file that’s typically part of extensions you might create. Firefox created this file, because it is typically expected. We’ll address what it’s used for shortly.

Note

If your extension folder is empty, you may have forgotten to restart Firefox. Restart your Firefox browser completely, and you’ll see these files in the extension folder.

So, here’s the long and short of it. By editing files directly in this folder, you won’t need to uninstall and reinstall the extension. Firefox automatically reloads extensions from this folder every time it is started, so if we need to make a change, we can simply edit the file and restart Firefox.

How the Firefox Interface Works

Just to get a bit of an understanding of how Firefox works, go ahead and point your Firefox browser to chrome://browser/content/browser.xul

Surprised? The components Firefox uses to generate its entire interface are entirely accessible to you. Chrome is a name used to describe the boxes and widgets of a program’s interface, and happens to be the convention Firefox followed when laying out their browser. Fortunately, all these layouts can be overlayed, meaning, we can force Firefox to load this interface, and then throw our own code on top of it.

To do this, we’re going to have to create a directory for this new GUI content. Within the extension directory, go ahead and create a directory chrome, and within that a directory content. Inside this directory, we can go ahead and create our first XUL file. Refer to Figure 2, “Extension File Structure” and make sure you follow the same structure.

Figure 2. Extension File Structure

Extension File Structure


Let’s create a file, and call it first_overlay.xul. Open it up, and let’s throw some code in there:

<?xml version="1.0"?>

<overlay id="my-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <statusbar id="status-bar">
    <statusbarpanel id="my-status-bar-panel">
      My Extension Works!
    </statusbarpanel>
  </statusbar>
</overlay>

Within this XUL file, we create an overlay object which contains a statusbar, and within that a statusbarpanel. The reason we need to define both objects is that a statusbar refers to the entire bar that sits at the bottom of your Firefox browser. The statusbarpanel is a single portion of that statusbar, much like the Windows menu may have a panel for the start button, the clock, and current applications open. Finally, within our statusbarpanel, we add the text “My Extension Works!”

These objects are defined initially by Mozilla, rather than being standard, so we’ll have to address Mozilla guidelines in setting attributes and manipulating the objects.

Save your XUL file. If you want to navigate to it, you’ll see that Firefox simply displays the text: “My Extension Works!” on a white background. While this isn’t particularly useful, it will at least pick up some basic errors if we were to make some syntactic mistakes.

chrome.manifest

Earlier, we noticed that Firefox generated a chrome.manifest file in our top directory for us. While we can access our XUL files in Firefox by navigating to the directory, the chrome.manifest file provies an easier route.

Open that file, and add this single line:

content newextension chrome/content/

This line tells Firefox to create a new chrome content directory called newextension, and to load the files within chrome/content into that directory. If you restart Firefox, you can now access our new XUL file by navigating to chrome://newextension/content/first_overlay.xul

Firefox now recognizes our XUL file as a part of its chrome library. This means that we can directly reference it with a local url. Now we can add an additional line to the chrome.manifest file:

overlay chrome://browser/content/browser.xul chrome://newextension/content/first_overlay.xul

This is an instruction that forces Firefox to overlay our first_overlay.xul file on top of the original browser.xul file that Firefox uses to render the browser window. Go ahead and restart Firefox now.

You’ve successfully created an overlay to the Firefox window. The phrase “My Extension Works!” now shows up in the bottom-right panel of the browser.

Adding New Behaviors

So far, we’ve discussed how to create an extension so that Firefox will recognize it, how to modify extensions without reinstalling, and how to modify Firefox’s interface with our own code. However, this is really only about half of what a Firefox extension is truly designed to do. We’ve changed the appearance of the Firefox application, now it’s time to modify its behavior.

To define actions, we’ll use Javascript. In the chrome/content directory of your extension, let’s create a new file extension_script.js.

Within this js file, we’ll create two functions:

function printMessage(message)
{
  alert(message);
}

function goToGoogle()
{
  gBrowser.selectedTab = gBrowser.addTab("http://www.google.com");
  printMessage('Welcome to Google');
}

To break this down, we’re creating the function printMessage to take in a variable, and then display an alert with the contents of that variable. The goToGoogle method creates a new Firefox tab, and makes it the selected tab. Then, the function calls the printMessage function to let the user know it has opened up Google for them. Now, we could have just as easily used the alert function in our goToGoogle function, but this shows us that we can chain these functions within our Javascript library.

The last thing we need to do is edit our overlay object that we defined in the first_overlay.xul file, because we need to load this Javascript file in order to use its functionality. We’ll also want to define the onclick parameter for our statusbarpanel:

<?xml version="1.0"?>

<overlay id="my-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <script type="application/x-javascript" src="chrome://newextension/content/extension_script.js"></script>
  <statusbar id="status-bar">
    <statusbarpanel id="my-status-bar-panel" onclick="goToGoogle()">
      My Extension Works!
    </statusbarpanel>
  </statusbar>
</overlay>

This additional code will load the library that now exists in chrome://newextension/content/extension_script.js, and instructs Firefox to call the goToGoogle() function whenever we click the statusbarpanel that we defined. This is all that you’ll need, so restart Firefox and click on the “My Extension Works!” text in the bottom right-hand corner. A new tab will open to Google, while Firefox displays an alert to inform you that you’re reached Google.

That’s all there is to it! Use standard Javascript to define actions, just like you would when working on a webpage. Most of the objects you’ll define in an overlay have parameters that you can map to various functions, such as the onclick parameter with our statusbarpanel.

Keeping Up Appearances

Well, you’re able to open new tabs, and display Javascript alerts. However, for displaying information to a user, we might want to come up with a design that we find suits our own style a bit better. Rather than using a Javascript alert, instead, we’ll create our own dialog to display some trivial information.

First, open up our extension_script.js file where we created those functions to load the Google tab, and display an alert. Let’s add an additional function:

function openNewDialog()
{
  window.openDialog("chrome://newextension/content/first_dialog.xul","newextension","chrome, dialog, modal, resizable=yes").focus();
}

We’re instructing the window to open up a new dialog as defined by the first_dialog.xul file in our content directory, and to bring that dialog into focus. However, we haven’t actually created that dialog yet, so let’s add a first_dialog.xul file to our directory:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>

<dialog id="new_dialog" title="My New Extension"
  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
  buttons="accept"
  persist="screenX screenY width height">
  <label id="title" value="My New Extension"/>
  <label value="Welcome, from our test dialog for our new extension!"/>
</dialog>

In this file, we first load an xml-stylesheet. This happens to be the global skin that comes with Firefox, but we could create our own if we wanted to, so as to adjust elements in our dialog.

Then, we define our dialog object, giving it an id, title, and setting a few attributes. Note that we set the buttons attribute to “accept”. In many cases, you may wish to use “accept,cancel”, but since we’re just displaying a message, rather than prompting the user for information, a single accept button is all we need.

Finally, we add two very simple objects, labels. The first displays the name of our extension, and the second just provides a short little message welcoming the user.

We created a function in our Javascript file to load this new dialog. However, nothing calls the function. Open up the first_overlay.xul file, and change the onclick attribute to openNewDialog(). Now, restart Firefox, and try clicking on our extension again. See Figure 3, “My New Extension Dialog”

Figure 3. My New Extension Dialog

My New Extension Dialog


Recall how I said at the beginning that Firefox extensions were just a combination of XUL, Javascript, and CSS? Well, let’s go ahead and create a style.css file in our content directory.

label#title {
  color: blue;
  font-size: 10pt;
}

Now we’ll change the font size and color for the label with the title id. Ultimately, you have the same options available to you as you do with HTML stylesheets. You’re simply editing XUL objects rather than HTML objects.

Now open up the first_dialog.xul file. We need to make sure to load this stylesheet so that it gets applied to our dialog. Normal CSS rules apply, so our paramters will override the default stylesheet. Let’s add a line after we load the global stylesheet:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
<?xml-stylesheet href="chrome://newextension/content/style.css" type="text/css"?>
<dialog id="new_dialog" title="My New Extension"
  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
  buttons="accept"
  persist="screenX screenY width height">
  <label id="title" value="My New Extension"/>
  <label value="Welcome, from our test dialog for our new extension!"/>
</dialog>

Restart Firefox, and you’ll see our dialog now reflects the new style update. See Figure 4, “My New Stylized Extension Dialog”

Figure 4. My New Stylized Extension Dialog

My New Stylized Extension Dialog


Let Me Google That For You

Without a doubt, there will be plenty of things you may want to add to your Firefox extension that we have not covered directly in this guide. However, there are many examples out on the web, along with documentation at the Mozilla Developer Center. Google will likely be an invaluable resource in learning how to write your extensions.

In this introduction, we’ve covered basic examples of how to implement the majority of functionality you’ll see in a Firefox extension. But since we haven’t covered every possible solution, let’s at least go through and write a fully functional example that can give us a chance to use all of the information we’ve just learned.

One recent website screaming for a Firefox extension is http://letmegooglethatforyou.com. This site was created by some developers who were frustrated at being asked repeated questions when the information could easily be found using a basic Google search. To close up this tutorial, we’ll go ahead and create an extension that helps us post to letmygooglethatforyou, so that when we’re expert developers, we can let point our own adoring fans in the right direction as well.

Create a new project folder and let’s start creating the contents.

install.rdf

<?xml version="1.0"?>

<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:em="http://www.mozilla.org/2004/em-rdf#">
  <Description about="urn:mozilla:install-manifest">
    <em:id>extension@letmegooglethatforyou.com</em:id>
    <em:version>0.0.1</em:version>
    <em:type>2</em:type>
    <em:targetApplication>
      <Description>
        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
        <em:minVersion>1.5</em:minVersion>
        <em:maxVersion>3.0.*</em:maxVersion>
      </Description>
    </em:targetApplication>
    <em:name>Let Me Google That For You Extension</em:name>
  </Description>
</RDF>

This is all content we’ve seen before. However, do make sure not to use the same id as the last example, or else Firefox will have collision issues.

With that out of the way, let’s start creating some content!

chrome/content

Create the subdirectories as with our last example, chrome/content. Within here, we’re going to create several new files.

browser_overlay.xul

<?xml version="1.0"?>

<overlay id="letmegooglethatforyou_overlay"
  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <script type="application/x-javascript" src="chrome://lmgtfy/content/lmgtfy.js"></script>
  <statusbar id="status-bar">
    <statusbarpanel id="lmgtfy_statusbarpanel" onclick="openLMGTFYPrompt()">
      <image src="chrome://lmgtfy/content/lmgtfy.ico" />
    </statusbarpanel>
  </statusbar>
</overlay>

This overlay is similar to the last example, except that in this case, we’re embedding an image, rather than the text “My Extension Works!” The image we reference is local, so we’ll have to make sure to include the lmgtfy.ico file so it gets loaded onto that bottom panel.

lmgtfy_prompt.xul

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
<?xml-stylesheet href="chrome://lmgtfy/content/style.css" type="text/css"?>

<dialog id="lmgtfy" title="Let Me Google That For You"
  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
  buttons="accept,cancel"
  ondialogaccept="doAccept();"
  persist="screenX screenY width height">

  <script type="application/x-javascript" src="chrome://lmgtfy/content/lmgtfy.js"></script>
  <groupbox>
    <dialogheader>Let Me Google That For You</dialogheader>
    <label value="What's your question?"/>
    <textbox id="search_params"/>
  </groupbox>
</dialog>

As in our last example, we’re creating a dialog. However, in this case, we’re also adding in a bit of Javascript. We use the script tag to load in the Javascript file we’ve defined. We also set the ondialogaccept parameter for the dialog itself to call the doAccept() function that we’ll define in our Javascript file. We include our elements inside a groupbox element, as another way of neatly ordering the items in our dialog.

lmgtfy.ico

I took the favicon.ico file directly from http://letmegooglethatforyou.com/favicon.ico, and converted it into a png file for display here. You can grab it from the original site, or simply save and rename the image here.

lmgtfy.js

function googleThatForMe(params)
{
  gBrowser.selectedTab =  gBrowser.addTab("http://www.letmegooglethatforyou.com/?q=" + params);
}

function openLMGTFYPrompt()
{
  var params = {};
  window.openDialog("chrome://lmgtfy/content/lmgtfy-prompt.xul","lmgtfy","chrome, dialog, modal, resizable=yes",params).focus()
  if(params.out){
    googleThatForMe(params.out.search);
  } else{
    // Do nothing (User clicked cancel)
  }
}

function doAccept()
{
  window.arguments[0].out = {search:document.getElementById("search_params").value};
}

Just like our last example, the Javascript is at the heart of creating a useful Firefox extension. Our first function, googleThatForMe(), takes in a variable and then opens up a tab to letmegooglethatforyou, adding on the param variable we passed in. So, if we were to call googleThatforMe("Firefox"), the Javascript would open a tab to http://www.letmegooglethatforyou.com/?q=Firefox, which happens to be the exact url pattern that letmegooglethatforyou uses.

Our second function, openLMGTFYPrompt(), loads our dialog that we defined in lmgtfy_prompt.xul, passing it an empty hash variable params. Then, if the dialog puts anything in the ‘out’ key of the params variable, it will call our googleThatForMe() function with the output data.

The last function, doAccept(), is called by our dialog when the user clicks the accept button. It takes the first object in the arguments array (which happens to be the params variable we passed in) and assigns the out key to whatever the user has entered into the search_params field that we’ve defined. This way the params variable is modified, and the openLMGTFYPrompt() function will call the googleThatForMe() function when the dialog returns.

style.css

dialogheader {
  background-image: url("chrome://lmgtfy/content/lmgtfy.ico");
  background-repeat: no-repeat;
  padding-left: 32px;
  height: 16px;
  width: 200px;
}

dialog {
  height: 300px;
}

In this case, we’re using standard CSS to style our lmgtfy_prompt.xul file. We set the height of the header to an appropriate height so that the image will display propertly, and set heights and widths such to display all the information, while giving the user enough space to type in their response.

chrome.manifest

There’s just one last piece to this extension before we’re ready to test it out. That’s right, the chrome.manifest file. Back in your extension directory, create the chrome.manifest file. Hopefully you’ve got a pretty good understanding of what should go in here. First, we’re going to instruct Firefox to create a new chrome directory, mapped to chrome/content/, and then we’re going to explicitly define an overlay on top of Firefox’s browser.xul file.

content lmgtfy chrome/content/
overlay chrome://browser/content/browser.xul chrome://lmgtfy/content/browser_overlay.xul

Once this is done, go ahead and zip up the contents of your folder, rename it to a .xpi file, and you should be all set to install. Enjoy your fully-functional Firefox extension! Figure 5, “Let Me Google That For You Dialog”

Figure 5. Let Me Google That For You Dialog

Let Me Google That For You Dialog


Wrapping It Up

You’ve learned a bunch of techniques in this introduction, beginning with basic XML, moving on to using XUL to define overlays the inject objects into Firefox’s interface. You added some Javascript to change how Firefox behaves, adding your own features. You learned how to create your own dialogs, and how to use standard CSS to adjust their appearance. Finally, we created a brand new extension that provides a new interface layer to an existing website. But the experience doesn’t end here! Be sure to head over to the Mozilla Developer Center to get a full picture of all the options available to you, from additional Javascript, to other XUL elements that we didn’t cover. Hopefully through these examples, you learned how you can build a full extension from a combination of basic standard tools. Happy developing!

Search