A PWA's offline behavior is a JavaScript and service-worker concern, but whether it's installable at all, what it's called, what icon it shows, and how much browser chrome survives installation are all determined at the HTML and manifest level ā the foundation this lesson covers.
1The Manifest: Declared In JSON, Linked From HTML
<link rel="manifest" href="/manifest.webmanifest"> in a page's <head> is the explicit connection between the HTML document and its web app manifest ā a JSON file declaring the app's name, start_url, icons, and display mode, among other fields. This link, combined with a registered service worker and the page being served over HTTPS, is what makes a browser's native install prompt (or an equivalent install affordance) available at all.
Without this link tag, none of the manifest's content matters ā the file can exist and be perfectly well-formed, but a browser has no way to discover and apply it without the explicit HTML-level connection.
2display Mode And Multi-Purpose Icons
The manifest's display field determines how much browser UI survives once the app is launched from its installed icon: "standalone" hides the browser's address bar and tab chrome while keeping the OS status bar, the classic native-app-like installed appearance; "fullscreen" goes further, also hiding the status bar; "minimal-ui" retains a small amount of browser navigation; and "browser" launches as an ordinary tab, unchanged from visiting the site directly.
Icons should be provided at multiple sizes (192Ć192 and 512Ć512 covering the common minimum), and specifically marking one with "purpose": "maskable" ā an icon authored with extra safe-zone padding around its essential content ā lets Android's adaptive-icon system safely crop it into a circle, squircle, or other device-theme-dependent shape without clipping anything important, alongside a standard, non-maskable icon for contexts that render icons unmasked.
3Service Worker Registration Differs From Every Other PWA Tag
Unlike the manifest, there is no dedicated HTML tag for registering a service worker ā it's always done imperatively in JavaScript, via navigator.serviceWorker.register('/sw.js'), typically inside a feature-detection check (if ("serviceWorker" in navigator)) and deferred until after the page's load event fires, so the registration doesn't compete with initial page rendering and resource loading for bandwidth and main-thread time.
Rounding out cross-platform consistency, apple-touch-icon (covered in the modern meta tags lesson) fills iOS's historical gap in sourcing its home-screen icon from the manifest, and theme_color/theme-color ā settable both inside the manifest and as a <meta> tag ā should generally be set in both places, since the meta tag governs browser-tab chrome while the manifest's value governs the installed, standalone-launch appearance.
4Step-by-Step Breakdown
Installability Starts In <head>, Not In JavaScript. A Progressive Web App's offline behavior lives in a service worker, but whether it's installable, what icon it shows, and how it looks once launched from a home screen are all determined by a JSON manifest and a handful of <head> tags ā the HTML-level foundation this lesson covers.
The Web App Manifest Is What Makes A Site Installable. A manifest.webmanifest JSON file, linked via <link rel="manifest">, declares the app's name, icons, start_url, and display mode ā its presence (alongside a registered service worker and HTTPS) is what triggers a browser's install prompt and defines how the app behaves once installed.
The Web App Manifest's Role. What links a page's HTML to its web app manifest?
- ā<link rel="manifest" href="..."> in the document head
- āA <meta name="manifest"> tag
- āBrowsers detect it automatically with no link required
display Mode Controls How Much Browser Chrome Survives Installation. The manifest's display field ā "standalone" (no browser UI, looks like a native app), "fullscreen" (also hides the OS status bar), "minimal-ui" (a few browser controls remain), or "browser" (a normal tab) ā determines exactly how much of the browser's own UI remains visible once the app is launched from its installed icon.
The display Manifest Field. Which display value gives an installed PWA the most native-app-like appearance, with no browser address bar or tab UI visible?
- ā"standalone"
- ā"browser"
- ā"minimal-ui", since it removes the most browser chrome
Multiple Icon Sizes And Purposes Across Platforms. The manifest's icons array should include multiple sizes (commonly including 192x192 and 512x512 at minimum) and can mark specific icons with purpose: "maskable" ā a maskable icon has extra padding so Android's adaptive-icon system can safely crop it into a circle, squircle, or other shape without clipping important content.
Maskable Icons. What problem does a maskable icon (purpose: "maskable") solve?
- āIt prevents important icon content from being clipped when an OS's adaptive-icon system crops it into a different shape
- āIt reduces the icon file's size on disk
- āIt automatically increases the icon's resolution
The Service Worker Is Registered From A <script>, Not Declared In HTML. Unlike the manifest, there's no dedicated HTML tag for service worker registration ā it's registered imperatively via navigator.serviceWorker.register('/sw.js') in a regular <script>, typically gated behind a feature-detection check and deferred until after the page's load event to avoid competing with initial page rendering for resources.
Service Worker Registration. Is there a dedicated HTML tag or attribute for registering a service worker, the way <link rel="manifest"> registers a manifest?
- āNo ā service worker registration is done imperatively via JavaScript, not declared in HTML
- āYes, a <link rel="serviceworker"> tag registers it declaratively
- āYes, via a dedicated <meta name="serviceworker"> tag
apple-touch-icon And theme-color Round Out Cross-Platform Support. Alongside the manifest, apple-touch-icon (covered in the modern meta tags lesson) fills iOS's historical gap in reading icons from the manifest directly, and theme-color ā settable both as a <meta> tag and inside the manifest itself ā keeps the installed app's system UI color consistent whether launched from a browser tab or its home-screen icon.
Cross-Platform PWA Consistency. Why does a well-configured PWA typically set theme_color in BOTH the manifest and as a <meta name="theme-color"> tag?
- āThe meta tag covers the browser-tab context; the manifest's value covers the installed, standalone-launch context
- āThere's no real reason; one of the two is always redundant
- āThe manifest version has fully deprecated the meta tag
HTML For PWAs Mastered. You now know how the web app manifest connects to your HTML, how display mode and maskable icons control the installed experience, and that service worker registration ā unlike the manifest ā is imperative JavaScript with no dedicated HTML tag.
Link The Web App Manifest. A PWA's installability starts with linking its manifest.json.
Level Up š
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1An Installed PWA's Accessibility Depends Entirely On The Same Underlying HTML Semantics Covered Throughout This Course
Installability doesn't introduce any separate accessibility model ā a PWA is exactly as accessible as its underlying HTML, semantic structure, and ARIA usage, whether viewed in a browser tab or launched standalone from a home screen icon.
SEO Implications
- 1
A Well-Configured Manifest And Installability Are Not Themselves Direct Search-Ranking Factors, But Correlate With Overall Site Quality Signals
Core Web Vitals and general page-experience quality (both covered elsewhere in this course) remain the actual ranking-relevant factors; PWA installability is a genuine user-experience and retention feature independent of any direct SEO effect.
Best Practices
Always Provide Both A Standard And A Maskable Icon, Not Maskable Alone
Contexts that render icons unmasked (some browser install UI, certain platforms) need a standard icon without the extra maskable safe-zone padding to look correctly proportioned.
Defer Service Worker Registration Until After The load Event
Registering immediately competes with initial page rendering and critical resource loading ā deferring it avoids that contention with no meaningful downside, since offline capability isn't typically needed in the first few moments of a page visit.
Frequent Bugs
A PWA's install prompt never appears despite having a seemingly correct manifest.webmanifest file.
Verify the manifest is actually linked via <link rel="manifest">, the page is served over HTTPS, and a service worker is genuinely registered ā all three are typically required together.
An app's icon appears with important content clipped off on Android devices using certain icon shape themes.
Add a dedicated maskable icon (purpose: "maskable") with sufficient safe-zone padding, alongside the existing standard icon.
Real-World Examples
A Complete Minimal PWA HTML/Manifest Setup
The full set of HTML-level and manifest pieces needed for a basic installable PWA.
<!-- index.html -->
<link rel="manifest" href="/manifest.webmanifest">
<link rel="apple-touch-icon" href="/icons/apple-touch-icon-180.png">
<meta name="theme-color" content="#0f172a">
<script>
if ("serviceWorker" in navigator) {
window.addEventListener("load", () => navigator.serviceWorker.register("/sw.js"));
}
</script>
// manifest.webmanifest
{
"name": "Acme Notes",
"start_url": "/",
"display": "standalone",
"theme_color": "#0f172a",
"icons": [
{ "src": "/icon-512.png", "sizes": "512x512", "type": "image/png" },
{ "src": "/icon-maskable.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" }
]
}