We'll want to create a file structure similar to the one above for our tutorial, so let's begin by creating a folder for your theme somewhere on your hard disk (e.g. C:\themes\my_theme\ or ~/themes/my_theme/). Inside your new theme folder, create two new empty text files, one called chrome.manifest and the other called install.rdf. The file preview.png is shown as a preview of the theme in the themes panel of the add-ons window. The file icon.png is used as an icon in the same panel. We'll leave both of them out for now, unless you have something picked out that you want to use.

The remaining directories will be extracted from the default theme. First, you'll want to create a directory somewhere. Copy your Firefox installation's omni.ja into this directory. The location differs by operating system:

Now, open (or unzip) this file into the directory you created. It contains several folders, modules, jssubloader and others. The files we will be needing are located under the chrome\toolkit\skin\classic folder.

Create a folder called chromein your theme's folder. Next, the contents of the following directories to their respective folders into the folder.

global to chrome/global

mozapps to chrome/mozapps

Now that you've copied the global and mozapps folders, a handful of other folders from the browser/omni.ja archive are required. It is located in the browser folder in the location mentioned above. The files we will be needing from the browser/omni.ja archive are located under chrome/browser/skin/classic.

Copy the contents of the following directories to their respective folders. This gives us a base set of styles to work with.

sample@example.net - the ID of the extension. This is a value you come up with to identify your extension in email address format (note that it should not be your email). Make it unique. You could also use a GUID. NOTE: This parameter MUST be in the format of an email address, although it does NOT have to be a valid email address. (example.example.example)

4 - the type of the add-on. '4' declares that it is installing a theme. If you were to install an extension it would be 2 (see Install Manifests#type for other type codes).

{ec8030f7-c20a-464f-9b0e-13a3a9e97384} - Firefox's application ID.

29.0 - the exact version number of the earliest version of Firefox you're saying this extension will work with. Never use a * in a minVersion, it almost certainly will not do what you expect it to.

32.* - the maximum version of Firefox you're saying this extension will work with. Set this to be no newer than the newest currently available version! In this case, "32.*" indicates that the extension works with Firefox 32 and any subsequent 32.x release. Themes are compatible by default, unless you set strict compatibility mode for your theme.

If you get a message that the install.rdf is malformed, it is helpful to load it into firefox using the File->Open File command and it will report XML errors to you.

See Install Manifests for a complete listing of the required and optional properties.

Save the file.

Styling the Browser's UI with CSS

Firefox's user interface is written in XUL and JavaScript. XUL is an XML grammar that provides user interface widgets like buttons, menus, toolbars, trees, etc. User actions are bound to functionality using JavaScript. These XUL elements are styled using CSS. If you don't know CSS, it's going to be a steep learning curve, and you may want to try some HTML-based tutorials to start with.

The browser UI has absolutely no styling on its own - if you try to start up with an empty theme, Firefox will be unusable, as the button elements will be drawn as plain text. This is why we copied the default styles in the setup step.

When writing a theme, the easiest way to determine what CSS selectors you need to write is to use the DOM Inspector which you should have installed in the setup step. You can use this to inspect any element in a web page or an XUL document, which makes it invaluable for themes.

Updating the toolbar's Styling

Note In Firefox 4.0 and up, the highlight feature of DOM Inspector is broken. To workaround this, disable Hardware Acceleration in Firefox' Options.

Open up the DOM Inspector now (located under the "Tools" menu), and go to "File->Inspect Chrome Document". This will be a menu containing all the XUL documents currently open in Firefox.
Pick the first document with a web page title, like "Firefox Start Page" and select it.

For this tutorial, we're going to update the background color of the toolbars. Select the node finding tool (the arrow-plus-box in the top-left corner of the DOM Inspector), and click on any unused space on a toolbar. This should select a node of type "xul:toolbar" in the DOM Inspector.

From here, you can play around with various different stylings for the toolbar and associated elements. By default, the right pane should show the DOM node, which has useful styling information like the CSS class and node id. The element itself is of id navigator-toolbox, with no idea. To change its style within our theme, we need to write a selector rule to select this class.

Open up the file chrome/browser/browser.css in your theme. Search this file for the #navigator-toolbox selector, and add a background: orange; rule to it.

Save the file.

Chrome URIs

Next, we have to tell Firefox where to find the theme files for your theme. CSS, XUL, and other files are part of "Chrome Packages" - bundles of user interface components which are loaded via chrome:// URIs. Rather than load the browser from disk using a file:// URI (since the location of Firefox on the system can change from platform to platform and system to system), Mozilla developers came up with a solution for creating URIs to content that the installed add-on knows about.

Firstly, the URI scheme (chrome) which tells Firefox's networking library that this is a Chrome URI. It indicates that the content of the URI should be handled as a (chrome). Compare (chrome) to (http) which tells Firefox to treat the URI as a web page.

Secondly, a package name (in the example above, browser) which identifies the bundle of user interface components.

Thirdly, the type of data being requested. There are three types: content (XUL, JavaScript, XBL bindings, etc. that form the structure and behavior of an application UI), locale (DTD, .properties files etc that contain strings for the UI's localization), and skin (CSS and images that form the theme of the UI)

Don't forget the trailing slash, "/"! Without it, the package won't be registered. The third column needs to match your theme's internalName value from the install manifest above.

This maps skin directories to locations within your theme. For example, the line skin browser sample skin/browser/ means "when the user has the sample theme selected, use the directory browser/ to look up skins for the browser package." More concisely, this means that the URL chrome://browser/skin/some/path/file.css will look for a file browser/some/path/file.css in your theme's root directory.

Save the file.

Test

First, we need to tell Firefox about your theme. During the development phase for Firefox versions 2.0 and higher, you can point Firefox to the folder where you are developing the theme, and it'll load it up every time you restart Firefox.

Locate your profile folder and beneath it the profile you want to work with (e.g. Firefox/Profiles/<profile_id>.default/).

Open the extensions/ folder, creating it if need be.

Create a new text file and put the full path to your development folder inside (e.g. C:\themes\my_theme\ or ~/themes/my_theme/). Windows users should retain the OS' slash direction, and everyone should remember to include a closing slash and remove any trailing spaces.

Save the file with the id of your theme as its name (e.g. sample@example.net). No file extension.

Now you should be ready to test your theme!

Start Firefox. Firefox will detect the text link to your theme directory and install the theme. Your theme will not be active the first time you install, and you will need to click "Enable" and restart before you can see your change. After it restarts this second time, you should see the background color of the toolbars is displayed in orange now.

You can now go back and make additional changes to your css files, close and restart Firefox, and see the updates.

Package

Now that your theme works, you can package it for deployment and installation.

Zip up the contents of your theme's folder (not the theme folder itself), and rename the zip file to have a .xpi extension. In Windows, you can do this easily by selecting all the files and subfolders in your extension folder, right click and choose "Send To -> Compressed (Zipped) Folder". A .zip file will be created for you. Just rename it and you're done!

Note: The command-line tool will update an existing zip file, not replace it - so if you have files you've deleted from your theme, be sure to remove the .xpi file before running the zip command again.

Now upload the .xpi file to your server, making sure it's served as application/x-xpinstall. You can link to it and allow people to download and install it. For the purposes of just testing our .xpi file we can just drag it into the Add-ons Manager via "Tools -> Add-ons Manager", or open it using "File -> Open File...".

Installing from a web page

There are a variety of ways you can install extensions from web pages, including direct linking to the XPI files and using the InstallTrigger object. Extension and web authors are encouraged to use the InstallTrigger method to install XPIs, as it provides the best experience to users.

Using addons.mozilla.org

Mozilla Add-ons is a distribution site where you can host your theme for free. Your theme will be hosted on Mozilla's mirror network to guarantee your download even though it might be very popular. Mozilla's site also provides users easier installation, and will automatically make your newer versions available to users of your existing versions when you upload them. In addition, Mozilla Add-ons allows users to comment and provide feedback on your theme. It is highly recommended that you use Mozilla Add-ons to distribute your themes!