Firefox themes are the easiest way to reshape the browser — and the most misunderstood part of Firefox customisation. Most guides either stop at “click Add to Firefox”, or they lump themes together with userChrome.css, which is a completely different mechanism.
This article does both differently. We did not research — we measured: counted the entire theme database on addons.mozilla.org, downloaded the 50 most-used themes and took their manifest.json apart, and built our own theme that Mozilla’s official addons-linter passes with zero errors, zero warnings, zero notices.
The result up front, and it is surprising in both directions: AMO holds 514,644 themes — more than five times the number of extensions. And a complete, valid theme comes to 528 bytes. One single file. No build step, no framework, not a line of JavaScript.
The short version
| Question | Answer (measured 31 Aug 2026) |
|---|---|
| How many Firefox themes exist? | 514,644 static themes on AMO |
| For comparison: extensions | 99,578 — themes are 5.2× more common |
| How large is a theme? | Our lint-clean theme: 528 bytes |
| Median size of the top 50 | 9,487 bytes (38 of 50 under 10 KB) |
| Do I need an image? | No — 37 of the top 50 use none at all |
| How many colour keys exist? | 42 according to the Firefox schema |
| How many do top themes use? | Median 26, minimum 2, maximum 38 |
| Do I need to code? | No — one manifest.json, nothing else |
| Must I publish it? | No, but permanent installation requires signing |
| Theme + extension in one package? | No — the linter fails hard |
| Is this the same as userChrome.css? | No — an entirely different mechanism |
/api/v5/addons/search/). The top 50 were downloaded as XPI, unpacked, and their manifest.json analysed. Linter results produced locally with addons-linter 10.10.0. Colour keys read from toolkit/components/extensions/schemas/theme.json in mozilla-central.
What a Firefox theme actually is
A theme is technically a WebExtension without code. It uses the same packaging as an extension — a ZIP archive containing a manifest.json — except there is no JavaScript inside, only colour definitions and optionally images.
Firefox distinguishes two kinds:
- Static themes never change after installation. They consist of the
themekey in the manifest. This is the normal case and the main subject here. - Dynamic themes are real extensions that call the
themeAPI and change appearance at runtime — by time of day, for instance, or by the website being visited.
The separation is strict, and it is not a matter of style but hard-enforced. Mozilla’s documentation puts it plainly:
“A theme and browser extension functionality cannot be defined in one package.” — extensionworkshop.com, Static themes, retrieved 31 Aug 2026
We verified this rather than believing it. Adding a browser_action key to an otherwise valid theme manifest and running the linter gives:
JSON_INVALID | "/" must NOT have additional properties
A hard error. You cannot ship a theme “alongside” an extension — if you want both, you need a dynamic theme with the theme permission.

Finding themes: 514,644 of them, and why that is not an advantage
The official home for themes is addons.mozilla.org (AMO). We asked the API what is actually there:
| Category on AMO | Count |
|---|---|
| Static themes | 514,644 |
| Extensions | 99,578 |
| Dictionaries | 250 |
| Language packs | 111 |
/api/v5/addons/search/?type=…&page_size=1, field count.
Half a million themes sounds like enormous choice. Mostly the number tells you how low the barrier is — and it falls apart on closer inspection.
We sampled the user-sorted ranking at several points:
| Rank in the list | Daily users |
|---|---|
| 1–50 | 11,021 – 307,731 |
| 451–500 | 715 – 798 |
| 2,451–2,500 | 69 – 71 |
| 4,951–5,000 | 26 – 27 |
| 9,951–10,000 | 10 |
| 14,951–15,000 | 5 – 6 |
| 19,951–20,000 | 3 |
| 24,951–25,000 | 2 |
| 29,951–30,000 | 2 |
sort=users, page_size=50, sampled at the pages listed, retrieved 31 Aug 2026.
At rank 30,000 a theme still has two daily users. And the measurement does not end there because the themes run out, but because the API stops at page 600 — page 601 returns {"detail":"Invalid page."}. The cap sits at exactly 30,000 entries; we determined that by binary search.
To find out what that means for the remaining 484,644 themes, we measured along a second axis: a sample of 300 themes sorted by creation date instead of by users.
| Sample metric (n = 300) | Value |
|---|---|
| Themes with zero daily users | 206 (69%) |
| Median daily users | 0 |
| Mean | 2.68 |
| Maximum in sample | 314 |
sort=created, fixed seed, 31 Aug 2026.
🔑 This is the real finding about choice: more than two thirds of all Firefox themes are used by nobody. The catalogue is not a curated collection, it is a storage location. That is not a criticism of Mozilla — it is the direct price of letting anyone create a theme in five minutes. But it means: the number 514,644 is worthless as a quality argument. If you want a good theme, do not be impressed by the total, sort by users and rating.

The strict filter: “Recommended” is rare
AMO marks add-ons that have passed extra review. We counted those too:
| Badge | Static themes |
|---|---|
| Recommended | 29 |
| Line (by Mozilla/partners) | 134 |
| Verified / Spotlight / Strategic | 0 |
?type=statictheme&promoted=…, 31 Aug 2026.
29 recommended themes out of 514,644 entries is a share of 0.0056%. If human review matters to you, your shortlist is very manageable. The “Recommended” filter on AMO is far more useful than any search query.
Installing themes
The process itself is unremarkable and takes three clicks:
- Open a theme on addons.mozilla.org.
- Click “Add to Firefox”.
- Done — themes request no permissions, so there is no consent dialogue listing rights.
Manage them under about:addons → Themes. Firefox also ships three built-in themes (System, Light, Dark) that appear in the same list. Only one theme can be active at a time.
The security angle here is genuinely relaxed: since a static theme contains no code and requests no permissions, it can neither read data nor make network requests. The worst a bad theme does is make text unreadable. If you want the wider picture on browser security and privacy, our article on open-source web browsers covers it.
Building your own Firefox theme — the minimal version
This is where it gets interesting, because the effort is absurdly small. A complete theme needs one single file.
Create a folder and put a manifest.json in it:
{
"manifest_version": 2,
"name": "GetMind Cosmic",
"version": "1.0",
"description": "A dark theme built as a live test for getmind.io",
"browser_specific_settings": {
"gecko": { "id": "getmind-cosmic@getmind.io" }
},
"theme": {
"colors": {
"frame": "#0b0f1a",
"tab_background_text": "#c9d1e8",
"tab_selected": "#161d33",
"tab_text": "#ffffff",
"tab_line": "#7c5cff",
"toolbar": "#111729",
"toolbar_text": "#e6ebff",
"toolbar_field": "#0b0f1a",
"toolbar_field_text": "#e6ebff",
"toolbar_field_border": "#2a3352",
"toolbar_field_focus": "#161d33",
"popup": "#111729",
"popup_text": "#e6ebff",
"popup_border": "#2a3352",
"ntp_background": "#0b0f1a",
"ntp_text": "#e6ebff",
"sidebar": "#111729",
"sidebar_text": "#e6ebff",
"icons": "#c9d1e8"
},
"properties": {
"color_scheme": "dark"
}
}
}
That is the whole thing. No npm install, no build step. We ran this manifest through Mozilla’s official checker:
npm install -g addons-linter
addons-linter .
Result: 0 errors, 0 warnings, 0 notices. Zipped, the theme is 528 bytes — with a header image it was 940 bytes. For comparison: the most-used image-based theme in the catalogue (Dark space) weighs 2.7 MB.
Try it immediately, no signing required
Nothing needs uploading to test:
- Open
about:debugging#/runtime/this-firefox - Click “Load Temporary Add-on…”
- Select the
manifest.json
The theme applies instantly. Important: it disappears on the next Firefox restart. For permanent installation there is no way around signing — more on that below.
The 42 colour keys
Firefox defines exactly 42 colour keys in its own schema. We read them straight out of theme.json in mozilla-central rather than copying a blog list. The important ones, grouped by area:
| Area | Keys |
|---|---|
| Window frame | frame, frame_inactive |
| Tabs | tab_selected, tab_text, tab_background_text, tab_line, tab_loading, tab_background_separator |
| Toolbar | toolbar, toolbar_text, bookmark_text, toolbar_top_separator, toolbar_bottom_separator, toolbar_vertical_separator |
| Address bar | toolbar_field, toolbar_field_text, toolbar_field_border, toolbar_field_focus, toolbar_field_text_focus, toolbar_field_border_focus, toolbar_field_highlight, toolbar_field_highlight_text |
| Icons | icons, icons_attention, button_background_hover, button_background_active |
| Menus/popups | popup, popup_text, popup_border, popup_highlight, popup_highlight_text |
| New tab | ntp_background, ntp_card_background, ntp_text |
| Sidebar | sidebar, sidebar_border, sidebar_text, sidebar_highlight, sidebar_highlight_text |
Three keys are deprecated and simply ignored by Firefox from version 70 or 89 onwards:
| Deprecated key | Replacement | Ignored since |
|---|---|---|
accentcolor | frame | Firefox 70 |
textcolor | tab_background_text | Firefox 70 |
toolbar_field_separator | — | Firefox 89 |
headerURL (image) | theme_frame | Firefox 70 |
Using accentcolor and textcolor today produces hard errors from the linter, not just warnings — we tested it. On current Firefox (154.0.1 at the time of writing) these aliases have been dead for over 80 releases.

How many colours do you actually need?
We downloaded the 50 most-used themes and analysed their manifests:
| Metric across the top 50 | Value |
|---|---|
| Themes with no image at all | 37 of 50 (74%) |
| Themes with images | 13 (12 using additional_backgrounds, 1 using theme_frame) |
| Colour keys used: median | 26 of 42 |
| Colour keys used: min / max | 2 / 38 |
| Package size: median | 9,487 bytes |
| Packages under 10 KB | 38 of 50 |
With a separate dark_theme block | 9 (18%) |
manifest.json analysed.
🔑 This contradicts the common assumption that a theme is primarily an image. Three quarters of the most successful themes are pure colour definitions — and the median is under 10 kilobytes. If you hear “theme” and picture a 4K panorama, you are picturing the exception.
The minimum of 2 colour keys is also notable. Two values are genuinely enough for a usable result: frame and tab_background_text. Firefox derives everything else. But setting only those two risks leaving menus and the address bar in default tones that clash — hence the median of 26.
Getting dark mode right
Many guides oversimplify here. There are two mechanisms and they do different things.
1. color_scheme — tells Firefox what kind of theme this is:
"properties": {
"color_scheme": "dark",
"content_color_scheme": "auto"
}
Allowed values are auto, light, dark and system. Among other things, this controls whether Firefox draws its own UI elements light or dark where the theme says nothing.
2. dark_theme — an entire second colour set:
{
"theme": { "colors": { "frame": "#ffffff", "tab_background_text": "#000000" } },
"dark_theme": { "colors": { "frame": "#000000", "tab_background_text": "#ffffff" } }
}
theme then applies in light system mode, dark_theme in dark mode, and Firefox switches automatically. That is exactly what profiles_blue, one of the most-used themes in the catalogue, does.
Only 9 of 50 top themes use this second block — the vast majority commit to one colour world. That is a legitimate design decision, but it means most themes ignore the user’s system mode.
The finding that surprised us most
While testing the linter we deliberately built broken manifests to see what it catches. The result splits in two — and the second half is a real trap.
What the linter reliably catches:
| Manipulation | Result |
|---|---|
theme_frame points to a missing file | Error |
headerURL instead of theme_frame (deprecated) | Error |
accentcolor / textcolor (deprecated) | Error |
color_scheme: "midnight" (invalid value) | Error |
| Colour value as a number instead of a string | Error |
browser_action next to theme | Error |
What the linter silently lets through:
| Manipulation | Result |
|---|---|
"toolbar": "dark-blue" (not a CSS colour name) | 0 errors, 0 warnings |
"toolbar": "#GGGGGG" (impossible hex) | 0 errors, 0 warnings |
"tab_text": "#12345" (five digits) | 0 errors, 0 warnings |
"tab_backgrund_text" (typo in the key) | 0 errors, 0 warnings, 0 notices |
addons-linter 10.10.0 against an otherwise valid theme, output evaluated in JSON format.
🔑 This is the most important practical finding in the article: a theme can pass the official checker cleanly and still look wrong. The cause is right there in the Firefox source. In ext-theme.js, colour values are not validated but passed through:
let cssColor = val;
if (Array.isArray(val)) {
cssColor = "rgb" + (val.length > 3 ? "a" : "") + "(" + val.join(",") + ")";
}
The value lands directly in a CSS property. If it is invalid, the ordinary CSS rule applies: the declaration is discarded and the element keeps its default colour. No crash, no console message, no red banner. Just a toolbar that looks exactly as it did before.
A typo in a key name is the same mechanism from the other direction: the schema permits additional properties inside the colors object, so tab_backgrund_text is formally fine — Firefox simply does not know the key and ignores it.
What this means in practice: a green linter run proves the structure is correct. It does not prove the colours arrive. The only reliable check is loading the theme temporarily via about:debugging and looking at it. Reading “0 errors” checks the packaging, not the contents.
This pattern shows up constantly in practice — tools reporting success while the actual goal is missed. If you want a documented case of that kind of silent false assumption, our article on IT security vulnerabilities describes one that went unnoticed for five days.
Images in a theme: what actually applies
If you do want an image, there are three keys under images:
| Key | Meaning |
|---|---|
theme_frame | The main image, anchored top right in the header area |
additional_backgrounds | Array of further images, individually positionable and tileable |
headerURL | Deprecated, ignored since Firefox 70 |
For positioning there is additional_backgrounds_alignment (13 values from top to right bottom) and additional_backgrounds_tiling (no-repeat, repeat, repeat-x, repeat-y).
On image size Mozilla is specific:
“The area your header image needs to fill is a maximum of 200 pixels high. […] Practically, this means you would need to allow for a width of up to 5120 pixels wide.” — extensionworkshop.com, Static themes
The advice in the same source, however, is not to build a 5120-pixel-wide image but a narrower one with a transparent left edge that fades into the background colour. That also explains why 12 of the 13 image-based top themes use additional_backgrounds rather than theme_frame: it makes tiling and soft transitions cleaner.
Worth knowing: we tested images at 6000×400 and 10×10 pixels — the linter reports nothing in either case. Image sizing is also a matter of looking, not of tooling.
Theme or userChrome.css? The distinction that matters
This is where most guides fall down, because they call both “customising Firefox”. Technically the two have almost nothing in common.
| Theme | userChrome.css | |
|---|---|---|
| What is it? | WebExtension without code | User stylesheet in the profile |
| What can it do? | Only colours and images of predefined areas | Arbitrary CSS across the whole interface |
| Change layout? | No | Yes — move, hide, rebuild elements |
| Enabled by default? | Yes | No, must be switched on first |
| Distributable? | Yes, via AMO, one click | Only as a file to copy manually |
| Signing required? | Yes (for permanent use) | No |
| Breaks on updates? | Practically never | Regularly |
| Audience | Everyone | Advanced users |
userChrome.css is disabled by default. That is not an assumption — we looked it up in Firefox’s own preference defaults:
// modules/libpref/init/all.js
pref("toolkit.legacyUserProfileCustomizations.stylesheets", false);
The name of the preference tells you Mozilla’s position: legacy. To use it you must:
- Open
about:configand settoolkit.legacyUserProfileCustomizations.stylesheetstotrue - In the profile folder (
about:support→ “Open Profile Folder”) create a folder namedchrome - Create
userChrome.cssinside it - Restart Firefox
The decisive drawback is not in the setup but in the future: userChrome.css targets internal Firefox selectors that Mozilla may change without notice. A Firefox update can render a customisation inert or wreck the interface at any time. A theme cannot suffer that — it uses a documented, stable interface.
The rule of thumb: want colours, use a theme. Want to change the layout — tab bar at the bottom, hidden elements, tighter spacing — you need userChrome.css and must accept the maintenance.

Without code: the AMO theme generator and Firefox Color
Not everyone wants to write JSON. Mozilla offers two graphical routes:
- AMO theme generator — in the developer area of addons.mozilla.org. Pick colours and an image, publish directly. A useful side effect per Mozilla’s docs: if you update your theme through the generator, you do not have to bump the version number manually.
- Firefox Color — try colours live in the browser, export the result as a shareable URL or as a finished add-on package.
Both produce the same manifest.json in the end. The difference is only the interface — and its limits: the UI does not expose all 42 colour keys and cannot do multiple images. For a theme that truly covers every area, you need the file.
Publishing on AMO
If the theme is to be installed permanently or shared, it must be signed. Mozilla is unambiguous:
“Static themes are built using a simple collection of files that are packaged and signed by addons.mozilla.org before they can be distributed and installed on Firefox.” — extensionworkshop.com, Static themes
The process:
- Build the package — zip the folder contents. Important:
manifest.jsonmust be at the top level of the archive, not inside a subfolder. - Check first —
addons-linter your-theme.zip. Saves a rejection round. - Upload — via the Developer Hub.
- Choose distribution — listed publicly on AMO, or self-distribution: you get a signed file back and distribute it yourself.
- Wait — themes are reviewed.
For updates: when uploading a package, the version must be higher than the current one, or AMO rejects it.

What gets rejected
The add-on policies name two concrete grounds for rejecting themes:
“Themes that feature low-quality, stretched, or blank images, as well as those themes in which the header image is misaligned, are not permitted.”
“Duplicate themes are not permitted.”
— extensionworkshop.com, Add-on Policies, as of 30 Apr 2026
The second point is why, with 514,644 themes already present and a usage rate of 31%, yet another “dark theme with a blue tint” makes little sense. It exists already, probably several times over.
Common mistakes and their causes
| Symptom | Likely cause |
|---|---|
| Theme installed but nothing changes | Invalid colour value — CSS discards it silently |
| One area stays the default colour | Typo in a key name (the linter does not report this!) |
| Theme gone after restart | Loaded temporarily via about:debugging |
| Text unreadable over the header image | tab_background_text not matched to the image |
| Menus clash with the rest | popup, popup_text, popup_border forgotten |
| Upload rejected | version not incremented, or ZIP with a subfolder |
Linter errors on accentcolor | Deprecated — replace with frame |
| Extension + theme does not work | Not permitted — you need a dynamic theme |
The second row is the most expensive one, because nothing ever reports it. Our advice from testing: after every change, load the theme via about:debugging and look at every area once — tab, address bar, an open menu, a new tab, the sidebar. Five glances that save an hour of searching.
Conclusion: small, safe, underrated
Firefox themes are that rare case of a customisation interface being exactly as simple as it looks. One file, no code, no permissions, 528 bytes. Anyone who has ever configured a CSS framework will be done in ten minutes.
The three things we learned by measuring that you will not read elsewhere:
- The half-million themes are not a selection, they are a storage location. 69% have zero users, and exactly 29 are Mozilla-recommended. Sort by users, not by recency.
- A theme is usually not an image. 37 of the 50 most-used themes contain no graphic at all, and the median is 9.5 KB.
- A green linter run is a statement about structure, not about outcome. Invalid colours and typos in key names pass it silently, because Firefox hands colour values to CSS unchecked.
And the distinction that saves the most time: colours → theme, layout → userChrome.css. Trying one with the other means fighting the wrong tool.
If you are curious how Firefox compares to other open-source browsers, read our deep dive on open-source web browsers. And if you are considering running more locally instead of in the cloud, running AI locally is a practical starting point.
Frequently asked questions about Firefox themes
What are Firefox themes?
Firefox themes are WebExtensions without program code that change the appearance of the browser interface. They consist of a manifest.json with a theme key defining colours for up to 42 predefined areas plus optional images. Because they contain no code and request no permissions, they cannot read data or make network requests.
How many Firefox themes are there?
On 31 Aug 2026 addons.mozilla.org held exactly 514,644 static themes — more than five times the number of extensions (99,578). That figure is misleading, though: in our sample 69% of themes had zero daily users, and only 29 themes carry the “Recommended” badge.
How do I create my own Firefox theme?
Create a folder and write a manifest.json inside it with manifest_version: 2, a name, a version and a theme object containing colour values. That is all — no build process, no JavaScript. To test, load the file via about:debugging#/runtime/this-firefox as a temporary add-on. Our finished example theme is 528 bytes when packaged.
Do I need an image for a Firefox theme?
No. Of the 50 most-used themes on AMO, 37 (74%) use no image at all and define only colours. The median package size is 9,487 bytes, and 38 of the 50 packages are smaller than 10 KB.
What is the difference between a theme and userChrome.css?
A theme changes only colours and images of predefined interface areas through a documented, stable interface. userChrome.css is a user stylesheet that applies arbitrary CSS to the entire Firefox interface, including layout changes. In exchange it is disabled by default (toolkit.legacyUserProfileCustomizations.stylesheets is set to false) and breaks regularly on Firefox updates because it relies on internal selectors.
Why does my theme not look right even though the linter reports no errors?
Because addons-linter does not validate colour values. We tested it: "toolbar": "dark-blue", "#GGGGGG" and "#12345" all pass with zero errors and zero warnings. Firefox hands the value to CSS unchecked — if it is invalid, CSS silently discards the declaration and the area keeps its default colour. The same applies to typos in key names such as tab_backgrund_text. The only reliable check is to load the theme temporarily and look at it.
How do I make a theme that adapts to dark mode?
Define two colour sets: theme for light system mode and dark_theme for dark mode. Firefox switches automatically. Additionally you can use "properties": { "color_scheme": "dark" } to control how Firefox draws its own elements. Only 9 of the 50 most-used themes use the dark_theme block.
Do I have to publish my theme with Mozilla?
Not for testing — about:debugging loads it temporarily, though it disappears on restart. For permanent installation the theme must be signed by addons.mozilla.org. You can choose between a public listing on AMO and self-distribution, where you distribute the signed file yourself.
Can I put a theme and an extension in one package?
No. Mozilla’s documentation rules it out and the linter enforces it: a browser_action key next to theme produces the hard error "/" must NOT have additional properties. If you need both, build a dynamic theme — a normal extension with the theme permission that sets the appearance at runtime.
Which colour keys are deprecated?
accentcolor (replaced by frame) and textcolor (replaced by tab_background_text) have been ignored since Firefox 70, as has the image field headerURL (replaced by theme_frame). toolbar_field_separator has been ignored since Firefox 89. The linter today reports the use of accentcolor and textcolor as errors, not merely warnings.
