Customizing the Firefox Bookmark Bar for Vanity
Everyone has a different way to customize and organize their web browsing. Personally I've found that the most effective way to get exactly to where I need to go is via lots of bookmarks with a lot of categorization. The rise of SPAs (Single Page Apps) does push many users towards not interacting as much with URLs. Despite that, deep-linking into applications still proves very effective at allowing users to get to resources rapidly.
To maximize the potential for bookmarks to act as a Second Brain the best options are probably use an external tool such as Pocket. If instead however, you want to manage a large number of bookmarks with a certain amount of flair, panache, and vanity keep on reading.
My final result; a pleasing mix of base favicons, single-link icons, and a bunch of chests for the folders

Step 0: Consolidate
To preface, I certainly did not do any consolidation prior to doing this process. It's not necessary, but you'll be better off for it. Firefox provides exports in at least two formats, though I'm sure there are more. The JSON format will look something like:
{
"guid": "root________",
"title": "",
"index": 0,
"dateAdded": 1679625667679000,
"lastModified": 1679625667870000,
"id": 1,
"typeCode": 2,
"type": "text/x-moz-place-container",
"root": "placesRoot",
"children": [
{
"guid": "menu________",
"title": "menu",
"index": 0,
"dateAdded": 1679625667679000,
"lastModified": 1679625667856000,
"id": 2,
"typeCode": 2,
"type": "text/x-moz-place-container",
"root": "bookmarksMenuFolder",
"children": [
{
"guid": "62ZrV0HO5zUB",
"title": "Mozilla Firefox",
"index": 0,
"dateAdded": 1517338628314000,
"lastModified": 1679787581000000,
"id": 7,
"typeCode": 2,
"type": "text/x-moz-place-container",
"children": [
{
"guid": "rY5l9_L250Ad",
"title": "Get Help",
"index": 0,
"dateAdded": 1651534099430000,
"lastModified": 1679787581000000,
"id": 8,
"typeCode": 1,
"iconUri": "fake-favicon-uri:https://support.mozilla.org/products/firefox",
"type": "text/x-moz-place",
"uri": "https://support.mozilla.org/products/firefox"
},
...
This may rapidly feel overwhelming, especially if, like me, you have multiple layers of folders named 'Imported from X' from switching browsers back and forth. Fortunately there are some tricks we can do to cheat. A major one is using `jq` to extract all the relevant values from the document. For example:
jq -r '.. | .uri? // empty' my_bookmarks.json
This command will recursively (due to the '..') visit all nodes and return the '.uri' property. The '-r' property specifies a raw return without wrapping quotation marks. The resulting output is just the bookmark urls.
https://www.mozilla.org/en-US/firefox/help/
https://www.mozilla.org/en-US/firefox/customize/
https://www.mozilla.org/en-US/contribute/
https://www.mozilla.org/en-US/about/
Other jq commands would allow for returning the '.title' or the tree structure for additional organization. For example if you wanted to retain the structure of the existing bookmarks including the title of the bookmark and folder:
## One-liner
jq 'walk(if(type == "object" and (has("uri") or has("children"))) then { title: .title, uri: .uri, children: .children } else .end)' my_bookmarks.json
## Formatted
jq 'walk(
if(type == "object" and (has("uri") or has("children")))
then { title: .title, uri: .uri, children: .children }
else .
end)' my_bookmarks.json
The result trims out all the fields that are likely not needed for the initial consolidation:
{
"title": "Mozilla Firefox",
"uri": null,
"children": [
{
"title": "Help and Tutorials",
"uri": "https://www.mozilla.org/en-US/firefox/help/",
"children": null
}
]
}
If JSON parsing isn't quite your speed, similar steps can be taken with the html output. Hilariously, because the output is so well formatted, running a quick Regex line-by-line parser would allow for grabbing both the titles (which are the element values) along with the hrefs. To satisfy the lawyers, other HTML regex parsing is explicitly discouraged.
Step 1: Locating The Settings
In the browser-bar, navigate to about:settings. The information that we are looking for is the
Profile directory for the
current user. On Ubuntu distributions for example, this could be located at /home/{name}/.mozilla/firefox/abcdefgh.default-release.
Opening this directory
will show us everything that Firefox stores for the given profile. For those with multiple profiles, this
process will need to be completed for each.
Step 2: Getting Stylish
Now that we have the profile directory, the next step is to add some style of our own to the equation. Within the
profile directory,
create a new directory named chrome. Within the new directory, create a file named userChrome.css.
Now, at this
point you may be scrolling up to check that yes, you're in the correct place, this is indeed a Firefox
tutorial. Why is this file
named referencing a certain product from a certain search company? No idea. But given what browsers send as
User-Agents, this both
par for the course and there is probably a titillating behind the scenes tale.
cd {profile directory} ## e.g. cd /home/funkhouser/.mozilla/firefox/abcdefgh.default-release
mkdir chrome
touch chrome/userChrome.css
The members of the online world are becoming more cognizant of the dangers of the internet. As such, more and more of our software is becoming locked down. Arguably this is a very good thing, but it means locking out some creativity. I think the best recent example of unbridled creativity is the launch of ChatGPT. The members of OpenAI had no idea how their product would be used and placed limited guardrails; the results were weird and wonderful.
To get to where I was going, Firefox is going to put a big scary message on your screen when we open the in-depth config. As such, it fees like my obligation to say: don't be stupid. Unless you find yourself continually tweaking these settings there is not need for concern. The reason this needs to be done right now is that Firefox by default no longer searches for this file on start-up. Supposedly this is for "performance reasons" since "no one uses this file" but I would just say, where's the fun in that?
In the in browser-bar, navigate to about:config. The property that we're looking for is toolkit.legacyUserProfileCustomizations.stylesheets.
Fortunately, despite the imposing empty box the page
starts with, just start typing "legacyUser" and the property should show up. At this point, it will probably be
false. Flip it to true,
likely via the switch button on the right, and that's it for the config
To see if it works, lets make some quick font adjustments. Putting the following within the new userChrome.css
file should provide a sense of what is controllable now.
* {
font-family: monospace; !important;
}
Unfortunately, Firefox doesn't reload this file automatically so make sure the entire Firefox process is closed (close all windows, on Mac do cmd+Q as well). After that, open Firefox back up and enjoy the mayhem of monospace!
Step 3: Finding some Material
Now that we've successfully updated the look and feel of Firefox, the time has come to make some choices about what the contents will be. Personally, I would strongly recommend finding a pixel art library that suites your needs. The rationale being that pixel art needs to convey meaning with a minimum of screen real-estate. An attribute which is very inline with a compact browser bar.
Myself, I went with a classic: the (video game) chest. These icons are from the wonderful game Terraria. Since I'm using their icons publicly, I will shamelessly plug it. It may have the largest value-to-content ratio I've ever seen in a game; and even goes on discount routinely.
One option is to extract the image assets directly from the game's resource packs. For a more general solution however,
we'll use python to download them from the wikipedia. Before that those, a quick admonishment: don't be an ass.
Server owners have to pay for the servers so don't just scrape with abandon. If done correctly, this should be a lesser burden than normal web traffic.
Now, lets get to querying images for a nicely formatted output. The simplest way may be to download the raw HTML
and then use some crafty multi-cursor logic to extract everything. Personally, I just wanted a subset of the lists
so I made a file named all_chests. A more flexible solution could use one of the many python
HTML scrapers. Think of the below code as a low-fidelity map.
/images/d/d9/Gold_Chest.png /images/b/b4/Frozen_Chest.png
import requests
import time
output_dir_path = "chests"
input_file = "all_chests"
host = "https://terraria.wiki.gg"
delay_s = 1.0
with open(input_file) as links_file:
seen_files = []
for link in links_file:
if not link in seen_files:
seen_files.append(link)
output_name = link.split("/")[-1].strip()
output_file_path = f"{output_dir_path}/{output_name}"
url = (host + link).strip()
print(f"Fetching {url} to {output_file_path}")
req = requests.get(url)
with open(output_file_path, "wb") as output_file:
output_file.write(req.content)
time.sleep(delay_s)
Step 4: Finding our Elements
For this styling, it's only possible to update existing elements via css; not create new ones. Since that's the case, we're going to need to know which elements we can style. As such, it's time to delve back to the ever dangerous world of Firefox config (or so Mozilla says). So, refrain from pasting javascript into your console some crypto-kid tells you will give you 10 bitcoins yea?
Go to about:config again and set two properties to true: (devtools.chrome.enabled and devtools.debugger.remote-enabled).
This will allow a new developer tools window (Browser Toolbox), with a connected debugger, for the
firefox-provided browser elements.
To launch this window, use the shortcut Ctrl+Alt+Shift+I or open the menu 'More Tools > Browser Toolbox'.
Take a moment. Poke around the xml tree and bask in your ability to read the secrets of the Matrix.
Back to business. If you've got tons of ideas about how to style your entire Firefox experience now, stop reading this and get to work. For the rest, we'll stay targeted on making our bookmark bars the envy of everyone who sees our browser on screen-share.
The first thing to do is to traverse to find the specific elements that we're interested in modifying. Starting from near the top (with many properties omitted for brevity) there should be something akin to:
<html:body>
<box id="navigator-toolbox-background">
<toolbox id="navigator-toolbox">
<vbox id="titlebar">...</vbox>
<toolbar id="nav-bar">...</toolbar>
<toolbar id="PersonalToolbar">
...
</toolbar>
</toolbox>
</box>
</html:body>
Hovering over each will show you the part of the browser screen that it references.
Inside the PersonalToolbar element, there will be elements controlling the structure of the
bookmarks.
Keep traversing the tree, and you'll find some elements with class="bookmark-item".
This is going to be the key to our bookmark endeavors.
Step 5: Layering on the Paint
The time has finally come to make our browser bar beautiful. This is my own preference of beauty of course, so feel free to disregard everything and paint your own style. First, we need to specify the exact element that we'd like to change. If the goal is to keep just an icon and remove the label, I would recommend keeping the label for now. Personally, some favicons are decent enough that I leave them as-is. In this case, just remove the label from the bookmark. For the rest, keep the label in place. The nice thing is that this label is encoded on the element itself. This means that we can target individual elements with CSS despite the fact that we cannot set an "id" on them. Then the label can be hidden with another CSS rule.
#personal-bookmarks .bookmark-item[label="Tool Links"] .toolbarbutton-icon {
/* Matches the size of the chest pngs */
width: 24px !important;
height: 21px !important;
padding: 0 !important;
margin: 0px !important;
/* The path to the image that you'll want to put. */
background: url("file:///Users/funkhouser/bookmark_images/chests/Golden_Chest.png") center center !important;
background-size: cover !important;
content: "Tool Links" !important;
list-style-image: none;
}
#personal-bookmarks .bookmark-item[label="Tool Links"] .toolbarbutton-text {
display: none !important;
}
Finally the magic sauce. This is what I've found to work well, but its certainly not the end-all-be-all and experimentation is recommended.
Its probably not surprising, but working with this styling can be finicky at best. If the images are slightly differently sized,
they might be cropped or they might expand the browser-bar height. Neither is particularly appealing, so working with a normalized
image-set is convenient.