[![Published on NPM](https://img.shields.io/npm/v/@khmyznikov/pwa-install.svg)](https://www.npmjs.com/package/@khmyznikov/pwa-install)
[![npm](https://img.shields.io/npm/dt/@khmyznikov/pwa-install)](https://www.npmjs.com/package/@khmyznikov/pwa-install)
## \<pwa-install\>

**New to PWAs? Unsure how to create a Web App? Check out these resources for a quick start: [PWA Intro](https://docs.pwabuilder.com/#/home/pwa-intro), [PWA Starter](https://docs.pwabuilder.com/#/starter/quick-start), [PWA Builder](https://www.pwabuilder.com/)**

Installation dialog for Progressive Web Application (PWA) and Add to Home Screen/Dock dialog for Web Apps. This offers an enhanced user experience and addresses the absence of native dialogs in certain browsers (Safari, Firefox, Opera, etc.). **28kB brotli** compressed bundle. Translation/localization is supported.

✨ **Now with iOS/iPadOS/MacOS 26+ support** for native look and feel!

Use it as [Web Component with any **modern** framework](https://custom-elements-everywhere.com/). No polyfill is required.
- [React <= 18 sample](https://stackblitz.com/edit/vite-react-ts-2eeiak?file=src%2FApp.tsx)
- [React 19+ sample](https://stackblitz.com/edit/react-19-web-components-shoelace-8rdjcfbb?file=src%2FApp.jsx)
- [Next.js 15 + React 19 sample](https://stackblitz.com/edit/github-xrnbtug5?file=src%2Fapp%2F(delete-this-and-modify-page.tsx)%2FPWAInstall.tsx)
- [Angular sample](https://stackblitz.com/edit/aozf92?file=package.json,src%2Fapp%2Fpwa-install%2Fpwa-install.component.html,src%2Fapp%2Fpwa-install%2Fpwa-install.component.ts)
- [Svelte](https://stackblitz.com/edit/svelte-tab-2-sng9wa?file=src%2Froutes%2F%2Bpage.svelte)
  
⚡Should work with any other modern framework or just vanila js as web component.

## **[Demo](https://khmyznikov.com/pwa-install/)**

## Gallery
| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iOS default&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Install instruction | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;App gallery&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
|-|-|-|
|![iOS example default](https://github.com/user-attachments/assets/933a9669-2b1a-49e1-ad49-b4d8657bee8c)|![iOS example install instruction](https://github.com/user-attachments/assets/7f7bf553-8c7e-4840-a261-28b07534ca07)|![iOS example gallery](https://github.com/user-attachments/assets/be709716-bcc4-457c-a271-4e6696032f57)|

| MacOS 14-26+ (Tahoe) |
|---|
|![macos_default](https://github.com/user-attachments/assets/c868fa2a-283e-4dcb-b6c5-b2bacdc1749e)|



| &nbsp;&nbsp;&nbsp;&nbsp;iPadOS&nbsp;&nbsp;&nbsp;&nbsp; | Instruction |
|---|---|
|![iPadOS example default](https://github.com/user-attachments/assets/a9b94313-7a88-4042-88c4-be7cc585e236)|![iPadOS install instruction](https://github.com/user-attachments/assets/0f62be23-ba2a-4bf9-b979-058487ccc238)



| Android | Firefox/ Opera/ Others | &nbsp;&nbsp;App gallery&nbsp;&nbsp; |
|-|-|-|
|![Android example default](https://github.com/user-attachments/assets/cd973d85-a7e7-4699-84c3-dc7c54aac146)|![Firefox Opera and others](https://github.com/user-attachments/assets/dc238509-96f6-4a8e-a8ba-7df0997a2c16)|![Android gallery](https://github.com/user-attachments/assets/98ac4107-c55b-464a-9881-bbc51721ac6d)|

| Chrome&nbsp; | App Gallery&nbsp;&nbsp; |
|---|---|
|![Chrome example default](https://github.com/user-attachments/assets/7406b3ff-4282-4a07-a3c1-e78f8949c00b)|![Chrome example gallery](https://github.com/user-attachments/assets/7c9722f1-0435-4901-ba21-d7e54b228022)|

<br>

## Install

```bash
npm i @khmyznikov/pwa-install
```

Alternatively, you can use [unpkg](https://unpkg.com) or [esm.sh](https://esm.sh).


## Import

```js
import '@khmyznikov/pwa-install';
```

## TS Config
```json
"compilerOptions": {
  "moduleResolution": "Bundler",
  "types": ["dom-chromium-installation-events", "web-app-manifest"]
}
```

## Use

```html
<pwa-install></pwa-install>
```
- [React <= 18 polyfill](https://stackblitz.com/edit/vite-react-ts-2eeiak?file=src%2FApp.tsx)
- [React 19+ sample](https://stackblitz.com/edit/react-19-web-components-shoelace-8rdjcfbb?file=src%2FApp.jsx)
- [Next.js 15 + React 19 sample](https://stackblitz.com/edit/github-xrnbtug5?file=src%2Fapp%2F(delete-this-and-modify-page.tsx)%2FPWAInstall.tsx)

### **[Demo](https://khmyznikov.com/pwa-install/)**

<br>

## Supported params
```html
<pwa-install
  manual-apple
  manual-chrome
  disable-chrome
  disable-close
  use-local-storage

  install-description="Custom call to install text"
  disable-install-description
  disable-screenshots
  disable-screenshots-apple
  disable-screenshots-chrome
  manual-how-to

  disable-android-fallback

  manifest-url="/manifest.json"
  name="PWA"
  description="Progressive web application"         
  icon="/icon.png">
</pwa-install>
<!-- 
  manual-apple/chrome params means you want to show the Dialog manually by showDialog().
  disable-chrome param is for completely disabling custom logic and interception for Chromium browsers (will work built-in browser logic).
  use-local-storage will store the user's preference to ignore the prompt in long-lived storage (so they will not be prompted again unless they clear application data)
  disable-android-fallback will disable instructions for non-Chrome browsers on Android
  manual-how-to shows the instructions right away, disabling screenshots (Apple only)
--->
```
*Make a good manifest file and don't use name/descr/icon params. Boolean attributes needs to be removed to act like "false"*

## Custom Styles

*Only the Apple template supports styling, and only the tint color option is available as of today. More to come.*
```html
<!-- As attribute (JSON string) -->
<pwa-install styles='{"--tint-color": "#6366f1"}'></pwa-install>
```

```javascript
// As property (object)
const pwaInstall = document.querySelector('pwa-install');
pwaInstall.styles = { '--tint-color': '#6366f1' };

// Or as attribute via JavaScript
pwaInstall.setAttribute('styles', JSON.stringify({ '--tint-color': '#6366f1' }));
```

<br>

## Supported events
- pwa-install-success-event
- pwa-install-fail-event
- pwa-install-available-event
- pwa-user-choice-result-event
- pwa-install-how-to-event
- pwa-install-gallery-event

```html
<script type="text/javascript">
  var pwaInstall = document.getElementsByTagName('pwa-install')[0];

  pwaInstall.addEventListener('pwa-install-success-event', (event) => {console.log(event.detail.message)});
</script>
```
⚠️ `success/fail/choice` events is Chromium only, iOS don't have them.

⚠️ If you see this message in the console:<br>
`Banner not shown: beforeinstallpromptevent.preventDefault() called. The page must call beforeinstallpromptevent.prompt() to show the banner.`<br>
This is **not** a error and **not** a bug. This means that the component successfully intercepted the *beforeinstallprompt* event.

<br>

## Supported properties (readonly)
- userChoiceResult: *string*
- isDialogHidden: *boolean*
- isInstallAvailable: *boolean*
- isAppleMobilePlatform: *boolean*
- isAppleDesktopPlatform: *boolean*
- isApple26Plus: *boolean*
- isUnderStandaloneMode: *boolean*
- isRelatedAppsInstalled: *boolean*

```html
<script type="text/javascript">
  var pwaInstall = document.getElementsByTagName('pwa-install')[0];

  console.log(pwaInstall.isUnderStandaloneMode);
</script>
```
<br>

## Supported methods
- install
- hideDialog
- showDialog
- getInstalledRelatedApps: async

```html
<script type="text/javascript">
  var pwaInstall = document.getElementsByTagName('pwa-install')[0];

  pwaInstall.install();
</script>
```

*getInstalledRelatedApps is Chromium only, always empty on iOS.*

<br>

## Async mode

If you need to target Chromium browsers but you want to postpone component mounting, you can do it!
But, need to capture *beforeinstallprompt* manually and pass it to the component's *externalPromptEvent* property(not attribute).

```javascript
// capture event asap, better right in index.html script tag
window.addEventListener('beforeinstallprompt', (e) => {
  e.preventDefault();
  e.stopPropagation();
  e.stopImmediatePropagation();

  // save it somewhere
  window.promptEvent = e;
});

// later render the component on demand and pass event
document.getElementById("pwa-install").externalPromptEvent = window.promptEvent;
```
<br>

## Supported localization

Translations available:
*EN*, *RU*, *TR*, *DE*, *ES*, *NL*, *EL*, *FR*, *SR*, *PL*, *ZH-CN*/*ZH-HK*, *IT*, *UK*, *CS*, *NO/NB*, *PT*, *JA*, *SV*, *KO*, *KM*, *DA*, *VI*, *FA*, *HU*, *SK*, *CA-ES*, *HE*

Language should change automatically based on browser settings. Please create the pull-request if you want to help with translation to your language. It's an easy process.

[Contribution Guidelines](./CONTRIBUTING.md)

<br>

## ROADMAP
- manual theme


[<img alt="buy me a coffee QR" src="https://github.com/khmyznikov/pwa-install/assets/6115884/5168f0db-2317-4ec2-8362-d828ffa2a8bf" width="200">](https://www.buymeacoffee.com/khmyznikov)
[<img alt="PayPal QR" src="https://github.com/khmyznikov/pwa-install/assets/6115884/6290b136-d525-4f8e-95fe-4729ea4c6414" width="200">](https://paypal.me/hmyznikov)

## One-time Backers ❤️
[Patrick Voigt](https://github.com/pvo13)<br>
[Darren Debono](https://github.com/amigabits)<br>
[Angelo Fan](https://github.com/angelofan)<br>
[Chris Cherniakov](https://github.com/Taequn)<br>
[Moddy](https://github.com/moddyio)<br>
[Pavlo Hromadchuk](https://github.com/hromadchuk)<br>
Leek Duck
