djc: thinking in writing

No Close Buttons

Or, How To Turn Your Firefox userChrome.css Hack Into a Neat Little Restart-Less Add-on, in Five Delightfully Simple Steps.

For as long as I can remember, I've had a small number of tweaks set in my Firefox profile's about:config. One of these was the browser.tabs.closeButtons pref, which I had set to 2. By default, Firefox shows a little close button on the right of every tab, but since I pretty much always use a keyboard shortcut to close tabs, these little buttons aren't that helpful, and they end up obscuring parts of their tab's titles. Setting the value to 2 removes all of the buttons.

In Firefox 31 (to be released to the general public in about 12 weeks), this preference has been removed, leading me to look into other ways of removing the buttons. A commenter on the bug noted the CSS required to remove the buttons again, saying that this could be added to the userChrome.css file in a profile. However, I don't really like that solution, since it would require me to port the fix to every computer I use, and it would be easy for me to lose it. Instead, I wanted to put it in an add-on, which would make it easy for me to install on other computers, in addition to being relatively easy to find. As an added benefit, others can benefit from the same add-on.

The result of this is the No Close Buttons add-on, which I put up on AMO yesterday. It was promptly reviewed by a friendly reviewer from the Dutch community, so that it can be installed without trouble. However, it's currently restricted to Firefox 31 and later, since I figured people on earlier versions wouldn't need it. Because it took me a while to piece together everything for what I thought should be a well-documented process (turning simple chrome CSS hacks into an add-on), I figured I'd document the process here.

First off, create a file called install.rdf:

<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
   - License, v. 2.0. If a copy of the MPL was not distributed with this
   - file, You can obtain one at http://mozilla.org/MPL/2.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>no-close-buttons@xavamedia.nl</em:id>
    <em:version>0.1</em:version>
    <em:type>2</em:type>
    <em:bootstrap>true</em:bootstrap>
    <em:unpack>false</em:unpack>
    <!-- Firefox -->
    <em:targetApplication>
      <Description>
        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
        <em:minVersion>31.0a1</em:minVersion>
        <em:maxVersion>31.0</em:maxVersion>
      </Description>
    </em:targetApplication>
    <!-- Front End MetaData -->
    <em:name>No Close Buttons</em:name>
    <em:description>Remove close buttons from tabs</em:description>
    <em:creator>Dirkjan Ochtman</em:creator>
  </Description>
</RDF>

Second, add a file named chrome.manifest, with a single line:

content              no-close-buttons        content/

Third, add some JavaScript code to register and unregister the stylesheet to a file named bootstrap.js:

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

'use strict';

var sss = Components.classes["@mozilla.org/content/style-sheet-service;1"].getService(Components.interfaces.nsIStyleSheetService);
var ios = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
var uri = ios.newURI('chrome://no-close-buttons/content/style.css', null, null);

function startup(data, reason) {
    sss.loadAndRegisterSheet(uri, sss.USER_SHEET);
}

function shutdown(data, reason) {
    sss.unregisterSheet(uri, sss.USER_SHEET);
}

Fourth, add your CSS, to the file named in your bootstrap.js. It should go inside the content directory you've already referenced in the manifest.

.tab-close-button { display: none !important; }

Fifth, and finally, if you zip up the four resulting items (install.rdf, chrome.manifest, bootstrap.js and the content directory), rename the resulting file so that its extension is xpi, and drop it into the extensions directory in your Firefox profile, Firefox should prompt you to install your new add-on!

I cobbled together all these bits and pieces by looking at a small add-on by Benjamin Smedberg (who has a number of UI-related add-ons up on AMO), some code from Stack Overflow, and MDN pages on bootstrapped add-ons and chrome registration. I put the result up on GitHub, any feedback is most welcome.