Platform in Platforms
Firefox taskbar web apps on Windows
Published Updated
Firefox 143 on Windows can pin a site to the taskbar and run it in a simplified window, a feature Mozilla ships under the name web apps and calls taskbar tabs in its own source. The pin is made from the address bar rather than from the site, and the window it opens keeps the profile and the container it was created with.
How it works
Section titled “How it works”The feature is one browser component, documented in the Firefox source tree as
Web Apps in Firefox.
That page states the feature is enabled by the preference browser.taskbarTabs.enabled,
and describes its entry point as a button on the URL bar rather than a manifest member or
a page API. The architecture document assigns that button to a module it calls the page
action, which shows and hides itself depending on whether the page has an HTTP or HTTPS
scheme.
Creating and removing the pin
Section titled “Creating and removing the pin”The component documentation gives both halves of the flow. Clicking the “Add tab to
taskbar” button on the URL bar creates a new window and prompts the user to pin it to the
taskbar. Clicking “Remove tab from taskbar” turns that window back into a normal tab and,
if that was the last window, unpins it from the taskbar. Firefox keeps information about
each web app in taskbartabs/taskbartabs.json inside the user’s profile, a file the same
page marks as intended for use internally by Firefox.
The icon is chosen the first time a web app is created, by iterating through sources (manifests, favicons) until a valid icon is found, and an existing web app saves its icon on the filesystem and loads it when needed. So the manifest and the favicon are where a site can influence what the taskbar shows.
What the pinned window carries over
Section titled “What the pinned window carries over”A pinned window is still the same browser. The “External Interactions” section of Web Apps in Firefox records the consequences that matter when you test an app there:
- Web apps are tied to the profile they are created with, so web app pages have the same access, controls and add-ons as a normal tab. The Firefox 143.0 release notes (September 16, 2025) describe this as pinning sites that run “without losing access to your installed add-ons”.
- Web apps are tied to the container, called a contextual identity in the source, they are created with, and launching via the taskbar reopens them in that container. The documentation presents this as a way for users to isolate sites without requiring a new profile per web app.
- Web app windows are not tied to the lifetime of normal browser session restore. They are not restored for users who have enabled “Open previous windows and tabs”, and they do not prevent the restoration of windows that session restore does handle.
Launching from the taskbar shortcut
Section titled “Launching from the taskbar shortcut”Clicking the taskbar shortcut starts Firefox with a command line, which the architecture document gives as:
firefox -taskbar-tab <id> -new-window <start url> -profile <profile path> -container <usercontextid>The same document records what happens when the referenced web app is absent: a new one is created, though not with that ID. When the web app exists its start URL is used, and otherwise the start URL from the shortcut opens instead, as a fallback.
Platform availability
Section titled “Platform availability”The component documentation lists web apps as available on Windows, both MSIX and non-MSIX, enabled by default, and on Linux, unsandboxed and under Flatpak, disabled by default. It states that macOS support is not available and gives the reason: macOS assumes that two different visible applications will be in two different processes, while Firefox web apps are in the same profile and process as the rest of the browser, so the Dock is not able to distinguish them. The architecture document adds that Linux under Snap is not supported.
The Firefox 143.0 release notes scope the shipped feature more narrowly than the component does. They describe it as a Windows feature and exclude Firefox installs from the Microsoft Store. Read the release notes for what Firefox 143 does, and the component documentation for where the component has reached since.
Examples
Section titled “Examples”A site cannot create the pin, so the code worth writing is the code that makes the simplified window a reasonable place to land.
Reacting when a window stops being a web app
Section titled “Reacting when a window stops being a web app”The architecture document puts “ejecting” web apps back into the tabs they came from in
TaskbarTabsWindowManager, so one window can change from an app surface back to a tab
while the page is loaded. A layout that keys on the
display-mode media feature
should therefore listen rather than read once.
The mode a Firefox taskbar web app reports is minimal-ui, not standalone:
TaskbarTabsWindowManager.sys.mjs
sets browser.browsingContext.displayMode = "minimal-ui"; on each tab of the window it
opens, and sets it to "browser" when the app is ejected. A check written against
standalone alone therefore reports a browser surface inside the window it meant to
detect, so test the installed modes as a set.
// Firefox taskbar web apps report minimal-ui. Other installed display modes depend// on the mode requested by the manifest and browser support.const APP_MODES = ['minimal-ui', 'standalone', 'window-controls-overlay'];
function trackAppSurface(onChange) { if (!('matchMedia' in window)) { // No matchMedia: render the browser layout and stop here. onChange('browser'); return () => {}; } const queries = APP_MODES.map((mode) => window.matchMedia(`(display-mode: ${mode})`)); const apply = () => onChange(queries.some((query) => query.matches) ? 'app' : 'browser'); apply(); queries.forEach((query) => query.addEventListener('change', apply)); return () => queries.forEach((query) => query.removeEventListener('change', apply));}
const stop = trackAppSurface((surface) => { document.documentElement.dataset.surface = surface;});Read the individual queries instead of the some() result when the distinction matters to
the layout: minimal-ui is the Firefox taskbar window, while the effective mode elsewhere
depends on the mode requested by the manifest and browser support. Keep the returned teardown function, because a single-page app
that re-runs this on every route change otherwise stacks one listener per navigation.
Serving the icon and name the pin will use
Section titled “Serving the icon and name the pin will use”Firefox uses the manifest’s name, start URL, scope, and icons. When no manifest icon is available, it also tries a favicon.
{ "name": "Example Reader", "short_name": "Reader", "start_url": "/app/", "scope": "/app/", "display": "standalone", "icons": [ { "src": "/icons/app-192.png", "sizes": "192x192", "type": "image/png" }, { "src": "/icons/app-256.png", "sizes": "256x256", "type": "image/png" }, { "src": "/icons/app-512.png", "sizes": "512x512", "type": "image/png" } ]}name, not short_name, is the string the registry entry carries:
TaskbarTabsRegistry.sys.mjs
creates it with name: manifest.name ?? generateName(aUrl), deriving a name from the URL
when the manifest has none. Keep short_name for the platforms that use it, and write a
name short enough to read under an icon.
The icon pass asks for 256 px: findBestManifestIcon in
TaskbarTabs.sys.mjs
discards icons whose purpose does not include any, sorts the rest by width, returns the
first candidate whose size is at least 256, and falls back to the largest candidate when
that search finds none. The same function substitutes Infinity for an empty or any
sizes value, so such an entry sorts above every pixel size. In the manifest above the
256 px icon is the one that search reaches, so serve a real asset at that size rather than
relying on a small favicon.
Observed behaviour
Section titled “Observed behaviour”The preference that gates the feature is set per platform in Firefox’s own default preference file, which is where the per-platform defaults above come from.
The address-bar entry point is drawn by the page action module, so a user whose build reads
the #else default has no button to click until the preference is changed. That is the
mechanism behind the Linux “disabled by default” line in the component documentation.
See also
Section titled “See also”- PWAs on Firefox
- PWAs on Windows
- PWAs on desktop
- display manifest member
- Web Apps in Firefox (firefox-source-docs.mozilla.org)
- Firefox 143.0 release notes (firefox.com)
- @media display-mode (developer.mozilla.org)
Specifications
| Specification | Status |
|---|---|
| None. | |