demo · v139
Install Button Component
A production-ready install button with a full state machine: not-installable, ready, installing, installed, and launch. Simulate each state to see the correct label, icon, and ARIA attributes update in real time.
Origin trial. To trigger a real install dialog: enable chrome://flags/#web-app-installation-api or join the origin trial. The simulator below works without the flag and shows every state transition.
live install button
simulate state
feature detection
—
checking navigator.install…
PWA install criteria
Run these checks to confirm your app meets the criteria before calling navigator.install().
- HTTPS (or localhost)not run
- Service worker registerednot run
- Web app manifest linkednot run
- navigator.install availablenot run
the code
class InstallButton extends HTMLElement {
#state = 'not-installable';
constructor() {
super();
this.#btn = this.attachShadow({ mode: 'open' })
.appendChild(document.createElement('button'));
window.addEventListener('beforeinstallprompt', e => {
e.preventDefault();
this.#deferredPrompt = e;
this.#setState('ready');
});
window.addEventListener('appinstalled', () => this.#setState('installed'));
}
async #handleClick() {
if (this.#state === 'ready') {
this.#setState('installing');
// Option A: beforeinstallprompt deferred prompt
if (this.#deferredPrompt) {
const { outcome } = await this.#deferredPrompt.prompt();
this.#setState(outcome === 'accepted' ? 'installed' : 'ready');
return;
}
// Option B: Web Install API (Chrome 139)
try {
const result = await navigator.install();
this.#setState(result?.mode === 'installed' ? 'installed' : 'ready');
} catch {
this.#setState('ready');
}
} else if (this.#state === 'installed') {
window.open(location.href, '_blank');
}
}
#setState(s) {
this.#state = s;
const labels = {
'not-installable': 'Install App',
'ready': 'Install App',
'installing': 'Installing…',
'installed': 'Open App',
};
this.#btn.textContent = labels[s];
this.#btn.setAttribute('aria-label', labels[s]);
this.#btn.disabled = s === 'not-installable' || s === 'installing';
}
}