Manifest member in Manifest
tabbed display mode and tab_strip manifest member
Published Updated
tabbed is a display mode that gives an installed app a tab strip inside its own window, so
the user can keep several in-scope pages open side by side without the browser’s address bar.
It is requested through display_override, not through display, and the companion
tab_strip member configures the strip: a pinned home tab with its own URL scope and the URL
the new-tab button opens.
Chrome 126, Edge 126, and Samsung Internet 28.0 process the value (BCD
html.manifest.display_override.tabbed); the Chrome for Developers page records the feature as
shipped on ChromeOS, and desktop Chrome on Windows, macOS, and Linux shows the strip for
installed apps from the same milestone. Firefox 157, Safari 27, and Android WebView skip the
entry and use the next display_override value or display.
Member
Section titled “Member”- Type:
"tabbed"is a string inside thedisplay_overridearray.tab_stripis an object with two optional keys:home_tab(false, or an object withscope_patterns, an array of URL pattern objects resolved against the manifest URL, andicons) andnew_tab_button(an object withurl, resolved against the manifest URL and required to be withinscope). - Default: without
tab_stripthe app behaves as{ "tab_strip": { "new_tab_button": { "url": "<start_url>" } } }and has no home tab.tab_stripis ignored unless the resolved display mode istabbed. - Example value:
"display_override": ["tabbed"]with"tab_strip": { "home_tab": { "scope_patterns": [{ "pathname": "/dashboard/*" }] }, "new_tab_button": { "url": "/new" } }.
The home tab is pinned: navigations to a URL matching one of its scope_patterns stay in it,
and navigations outside those patterns open a new app tab. When home_tab is present but
scope_patterns is absent, the home tab’s scope collapses to start_url alone. The new-tab
button is only rendered when its url falls outside the home tab’s scope; a url inside it
hides the button, because the home tab already covers that destination (WICG explainer).
Examples
Section titled “Examples”The three manifests describe the same project-management app with a dashboard at
/dashboard/ and per-project pages at /projects/<id>/.
Opting in with a standalone fallback
Section titled “Opting in with a standalone fallback”tabbed goes first in display_override; display stays standalone so Chrome 125,
Firefox, and Safari launch an ordinary app window. Nothing else is required for a working tab
strip, because the default tab_strip opens new tabs at start_url.
{ "start_url": "/dashboard/", "scope": "/", "display": "standalone", "display_override": ["tabbed"]}With this manifest every link to a project page opens in a new app tab, and the dashboard is just one tab among them, closable like any other.
Pinning the dashboard as the home tab
Section titled “Pinning the dashboard as the home tab”Adding home_tab turns the dashboard into a pinned first tab that stays open and that
absorbs every navigation under /dashboard/. The new-tab button points at /projects/new,
which is outside the home tab’s patterns, so the button is shown.
{ "start_url": "/dashboard/", "scope": "/", "display": "standalone", "display_override": ["tabbed"], "tab_strip": { "home_tab": { "scope_patterns": [{ "pathname": "/dashboard/*" }], "icons": [{ "src": "/icons/home-96.png", "sizes": "96x96" }] }, "new_tab_button": { "url": "/projects/new" } }}Pointing new_tab_button.url at /dashboard/ instead would hide the button, since that
destination is already the home tab.
Adapting navigation to the mode the browser chose
Section titled “Adapting navigation to the mode the browser chose”A tabbed app can let the OS tab strip replace an in-page tab bar, but only when the mode was granted. The check runs at startup and again on change, because the user can move the window between modes.
const tabbed = matchMedia('(display-mode: tabbed)');
function applyMode(active) { document.documentElement.dataset.nav = active ? 'os-tabs' : 'in-page';}
applyMode(tabbed.matches);tabbed.addEventListener('change', (event) => applyMode(event.matches));With data-nav="in-page" the app renders its own tab bar; with os-tabs it hides that bar
and opens project pages with window.open(url) so each becomes an app tab.
See also
Section titled “See also”- display_override manifest member
- display manifest member
- Desktop PWA installation: Chrome, Edge, and beyond
- Manifest Incubations: tabbed application mode explainer (wicg.github.io)
- Tabbed application mode for PWAs (developer.chrome.com)
Specifications
| Specification | Status |
|---|---|
| Web App Manifest: display_override "tabbed" mode | WICG draft |
| Manifest Incubations: display_override member | WICG draft |
- Legend
- Yes
- Partial
- Flag
- No
- Unknown
| Browser / Platform | Support | Versions | Confidence | Source | Notes |
|---|---|---|---|---|---|
| Chrome (Desktop) | Yes | 126 | high | source | — |
| Chrome (Android) | Yes | 126 | high | source | 1 |
| Edge (Desktop) | Yes | 126 | high | source | 2 |
| Firefox (Desktop) | No | — | high | source | 3 |
| Firefox (Android) | No | — | high | source | 45 |
| Safari (macOS) | No | — | high | source | 6 |
| Safari (iOS) | No | — | high | source | 78 |
| Samsung Internet | Yes | 28.0 | high | source | 9 |
| WebView (Android) | No | — | high | source | 10 |
- Derived by browser-compat-data mirroring from Chrome.
- Derived by browser-compat-data mirroring from Chrome.
- No Firefox support is recorded in browser-compat-data.
- No Firefox for Android support is recorded in browser-compat-data.
- Derived by browser-compat-data mirroring from Firefox.
- No Safari support is recorded in browser-compat-data.
- No Safari on iOS support is recorded in browser-compat-data.
- Derived by browser-compat-data mirroring from Safari.
- Derived by browser-compat-data mirroring from Chrome Android.
- No WebView Android support is recorded in browser-compat-data.