@progressivewebcomponents/pwa-install
Version:
A tiny vanilla (zero-dependency) non-visual native browser web component (plug-n-play custom HTML element and extensible class) that helps implement custom patterns for promoting progressive web apps (PWA) installation
707 lines (526 loc) • 19.1 kB
Markdown
[](https://npmjs.com/package/@progressivewebcomponents/pwa-install)
[](https://webcomponents.org/element/@progressivewebcomponents/pwa-install)
A tiny vanilla (zero-dependency) non-visual native browser web component (plug-n-play custom HTML element and extensible class) that helps implement [custom patterns for promoting progressive web apps (PWA) installation](https://web.dev/articles/promote-install).
It's compatible with [Google Polymer](https://polymer-library.polymer-project.org) library data binding.
# Table of contents
- [API](#api)
* [Methods](#methods)
* [Properties](#properties)
* [Attributes](#attributes)
* [Events](#events)
- [Install](#install)
- [Import](#import)
* [Local](#local)
+ [JS](#js)
+ [HTML](#html)
+ [Import maps](#import-maps)
- [JS](#js-1)
- [HTML](#html-1)
+ [Dev Servers / Builders](#dev-servers--builders)
- [JS](#js-2)
- [HTML](#html-2)
* [CDN](#cdn)
+ [UNPKG](#unpkg)
- [JS](#js-3)
- [HTML](#html-3)
+ [ESM CDN](#esm-cdn)
- [JS](#js-4)
- [HTML](#html-4)
+ [Skypack](#skypack)
- [JS](#js-5)
- [HTML](#html-5)
- [Use](#use)
* [HTML](#html-6)
* [JS](#js-6)
+ [Use case](#use-case)
+ [Use case](#use-case-1)
* [CSS](#css)
+ [Use case](#use-case-2)
* [Lit](#lit)
* [Polymer](#polymer)
+ [Use case](#use-case-3)
- [Customize](#customize)
- [Further reading](#further-reading)
# API
## Methods
| Method | Type | Modifiers |
|---------------------------|------------------------|-----------|
| `prompt` | `(): ?Promise<Object>` | async |
| `getInstalledRelatedApps` | `(): ?Promise<Array>` | async |
## Properties
| Property | Type | Modifiers |
|--------------------------------------|------------|-----------|
| `isInstallSupported` | `?boolean` | readonly |
| `isInstallAvailable` | `?boolean` | readonly |
| `platforms` | `?Array` | readonly |
| `choiceResult` | `?Object` | readonly |
| `isGetInstalledRelatedAppsSupported` | `?boolean` | readonly |
| `relatedApps` | `?Array` | readonly |
## Attributes
| Attribute | Type | Modifiers |
|-------------------------------------------|------------|-----------|
| `is-install-supported` | `?boolean` | readonly |
| `is-install-available` | `?boolean` | readonly |
| `is-get-installed-related-apps-supported` | `?boolean` | readonly |
## Events
| Event | Bubbles | Composed |
|---------------------------------------------------|---------|----------|
| `pwa-install-available` | true | true |
| `pwa-install-installing` | true | true |
| `pwa-install-installed` | true | true |
| `pwa-install-error` | true | true |
| `is-install-supported-changed` | false | false |
| `is-install-available-changed` | false | false |
| `platforms-changed` | false | false |
| `choice-result-changed` | false | false |
| `is-get-installed-related-apps-supported-changed` | false | false |
| `related-apps-changed` | false | false |
# Install
```sh
npm i @progressivewebcomponents/pwa-install
```
# Import
## Local
### JS
```js
import './node_modules/@progressivewebcomponents/pwa-install/pwa-install.js';
```
<details>
<summary>Advanced usage</summary>
See the [Customize](#customize) section for how to use the code below:
```js
import { PWAInstall } from './node_modules/@progressivewebcomponents/pwa-install/pwa-install-class.js';
```
</details>
### HTML
```html
<script
type="module"
src="./node_modules/@progressivewebcomponents/pwa-install/pwa-install.js"
>
</script>
```
```html
<script type="module">
import './node_modules/@progressivewebcomponents/pwa-install/pwa-install.js';
</script>
```
<details>
<summary>Advanced usage</summary>
See the [Customize](#customize) section for how to use the code below:
```html
<script type="module">
import { PWAInstall } from './node_modules/@progressivewebcomponents/pwa-install/pwa-install-class.js';
</script>
```
</details>
### Import maps
```html
<script type="importmap">
{
"imports": {
"pwa-install": "./node_modules/@progressivewebcomponents/pwa-install/pwa-install.js",
"pwa-install/": "./node_modules/@progressivewebcomponents/pwa-install/"
}
}
</script>
```
#### JS
```js
import 'pwa-install';
```
<details>
<summary>Advanced usage</summary>
See the [Customize](#customize) section for how to use the code below:
```js
import { PWAInstall } from 'pwa-install/pwa-install-class.js';
```
</details>
#### HTML
```html
<script type="module">
import 'pwa-install';
</script>
```
<details>
<summary>Advanced usage</summary>
See the [Customize](#customize) section for how to use the code below:
```html
<script type="module">
import { PWAInstall } from 'pwa-install/pwa-install-class.js';
</script>
```
</details>
### Dev Servers / Builders
#### JS
```js
import '@progressivewebcomponents/pwa-install';
```
<details>
<summary>Advanced usage</summary>
See the [Customize](#customize) section for how to use the code below:
```js
import { PWAInstall } from '@progressivewebcomponents/pwa-install/pwa-install-class.js';
```
</details>
#### HTML
```html
<script type="module">
import '@progressivewebcomponents/pwa-install';
</script>
```
<details>
<summary>Advanced usage</summary>
See the [Customize](#customize) section for how to use the code below:
```html
<script type="module">
import { PWAInstall } from '@progressivewebcomponents/pwa-install/pwa-install-class.js';
</script>
```
</details>
## CDN
### UNPKG
#### JS
```js
import 'https://unpkg.com/@progressivewebcomponents/pwa-install';
```
<details>
<summary>Advanced usage</summary>
See the [Customize](#customize) section for how to use the code below:
```js
import { PWAInstall } from 'https://unpkg.com/@progressivewebcomponents/pwa-install/pwa-install-class.js';
```
</details>
#### HTML
```html
<script
type="module"
src="https://unpkg.com/@progressivewebcomponents/pwa-install"
>
</script>
```
```html
<script type="module">
import 'https://unpkg.com/@progressivewebcomponents/pwa-install';
</script>
```
<details>
<summary>Advanced usage</summary>
See the [Customize](#customize) section for how to use the code below:
```html
<script type="module">
import { PWAInstall } from 'https://unpkg.com/@progressivewebcomponents/pwa-install/pwa-install-class.js';
</script>
```
</details>
### ESM CDN
#### JS
```js
import 'https://esm.sh/@progressivewebcomponents/pwa-install';
```
<details>
<summary>Advanced usage</summary>
See the [Customize](#customize) section for how to use the code below:
```js
import { PWAInstall } from 'https://esm.sh/@progressivewebcomponents/pwa-install/pwa-install-class.js';
```
</details>
#### HTML
```html
<script
type="module"
src="https://esm.sh/@progressivewebcomponents/pwa-install"
>
</script>
```
```html
<script type="module">
import 'https://esm.sh/@progressivewebcomponents/pwa-install';
</script>
```
<details>
<summary>Advanced usage</summary>
See the [Customize](#customize) section for how to use the code below:
```html
<script type="module">
import { PWAInstall } from 'https://esm.sh/@progressivewebcomponents/pwa-install/pwa-install-class.js';
</script>
```
</details>
### Skypack
#### JS
```js
import 'https://cdn.skypack.dev/@progressivewebcomponents/pwa-install';
```
<details>
<summary>Advanced usage</summary>
See the [Customize](#customize) section for how to use the code below:
```js
import { PWAInstall } from 'https://cdn.skypack.dev/@progressivewebcomponents/pwa-install/pwa-install-class.js';
```
</details>
#### HTML
```html
<script
type="module"
src="https://cdn.skypack.dev/@progressivewebcomponents/pwa-install"
>
</script>
```
```html
<script type="module">
import 'https://cdn.skypack.dev/@progressivewebcomponents/pwa-install';
</script>
```
<details>
<summary>Advanced usage</summary>
See the [Customize](#customize) section for how to use the code below:
```html
<script type="module">
import { PWAInstall } from 'https://cdn.skypack.dev/@progressivewebcomponents/pwa-install/pwa-install-class.js';
</script>
```
</details>
# Use
## HTML
```html
<pwa-install id="a2hs"></pwa-install>
```
## JS
```js
const pwaInstall = document.getElementById('a2hs');
```
```js
const choiseResult = await pwaInstall.prompt();
const relatedApps = await pwaInstall.getInstalledRelatedApps();
```
```js
let isInstallSupportedPropertyValue = pwaInstall.isInstallSupported;
let isInstallAvailablePropertyValue = pwaInstall.isInstallAvailable;
let platformsPropertyValue = pwaInstall.platforms;
let choiceResultPropertyValue = pwaInstall.choiceResult;
let isGetInstalledRelatedAppsSupportedPropertyValue = pwaInstall.isGetInstalledRelatedAppsSupported;
let relatedAppsPropertyValue = pwaInstall.relatedApps;
```
```js
let isInstallSupportedAttributeValue = pwaInstall.hasAttribute('is-install-supported');
let isInstallAvailableAttributeValue = pwaInstall.hasAttribute('is-install-available');
let isGetInstalledRelatedAppsSupportedAttributeValue = pwaInstall.hasAttribute('is-get-installed-related-apps-supported');
```
```js
pwaInstall.addEventListener('pwa-install-available', handlePWAInstallAvailableEvent);
pwaInstall.addEventListener('pwa-install-installing', handlePWAInstallInstallingEvent);
pwaInstall.addEventListener('pwa-install-installed', handlePWAInstallInstalledEvent);
pwaInstall.addEventListener('pwa-install-error', handlePWAInstallErrorEvent);
```
```js
const handlePWAInstallAvailableEvent = (event) => {
// Use event.detail.value and/or run any code
}
const handlePWAInstallInstallingEvent = (event) => {
// Use event.detail.value and/or run any code
}
const handlePWAInstallInstalledEvent = (event) => {
// Use event.detail.value and/or run any code
}
const handlePWAInstallErrorEvent = (event) => {
// Use event.detail.message.error, event.detail.value and/or run any code
}
```
### Use case
Events can be used to collect telemetry on (promoting) PWA installation and send it to e.g. Google Analytics:
```js
const handlePWAInstallAvailableEvent = (event) => {
window.gtag?.('event', 'pwa-install', {
'state': 'available',
'platforms': event.detail.value,
});
}
const handlePWAInstallInstallingEvent = (event) => {
window.gtag?.('event', 'pwa-install', {
'state': 'installing',
'outcome': event.detail.value?.outcome,
'platform': event.detail.value?.platform,
});
}
const handlePWAInstallInstalledEvent = (event) => {
window.gtag?.('event', 'pwa-install', {
'state': 'installed',
'platform': event.detail.value?.platform,
});
}
const handlePWAInstallErrorEvent = (event) => {
window.gtag?.('event', 'pwa-install', {
'state': 'error',
'error': event.detail.message.error,
'platform': event.detail.value?.platform,
});
}
```
```js
pwaInstall.addEventListener('is-install-supported-changed', handleIsInstallSupportedPropertyChangedEvent);
pwaInstall.addEventListener('is-install-available-changed', handleIsInstallAvailablePropertyChangedEvent);
pwaInstall.addEventListener('platforms-changed', handlePlatformsPropertyChangedEvent);
pwaInstall.addEventListener('choice-result-changed', handleChoiceResultPropertyChangedEvent);
pwaInstall.addEventListener('is-get-installed-related-apps-supported-changed', handleIsGetInstalledRelatedAppsSupportedPropertyChangedEvent);
pwaInstall.addEventListener('related-apps-changed', handleRelatedAppsPropertyChangedEvent);
```
```js
const handleIsInstallSupportedPropertyChangedEvent = (event) => {
// Use event.detail.value and/or run any code
}
const handleIsInstallAvailablePropertyChangedEvent = (event) => {
// Use event.detail.value and/or run any code
}
const handlePlatformsPropertyChangedEvent = (event) => {
// Use event.detail.value and/or run any code
}
const handleChoiceResultPropertyChangedEvent = (event) => {
// Use event.detail.value and/or run any code
}
const handleIsGetInstalledRelatedAppsSupportedPropertyChangedEvent = (event) => {
// Use event.detail.value and/or run any code
}
const handleRelatedAppsPropertyChangedEvent = (event) => {
// Use event.detail.value and/or run any code
}
```
### Use case
Events can be used to update the property values:
```js
const handleIsInstallSupportedPropertyChangedEvent = (event) => {
isInstallSupportedPropertyValue = event.detail.value;
}
const handleIsInstallAvailablePropertyChangedEvent = (event) => {
isInstallAvailablePropertyValue = event.detail.value;
}
const handlePlatformsPropertyChangedEvent = (event) => {
platformsPropertyValue = event.detail.value;
}
const handleChoiceResultPropertyChangedEvent = (event) => {
choiceResultPropertyValue = event.detail.value;
}
const handleIsGetInstalledRelatedAppsSupportedPropertyChangedEvent = (event) => {
isGetInstalledRelatedAppsSupportedPropertyValue = event.detail.value;
}
const handleRelatedAppsPropertyChangedEvent = (event) => {
relatedAppsPropertyValue = event.detail.value;
}
```
## CSS
```css
#a2hs[is-install-supported]
#a2hs[is-install-available]
#a2hs[is-get-installed-related-apps-supported]
```
### Use case
CSS attribute selectors can be used to show/hide and/or style other HTML elements e.g. the UI for promoting PWA installation:
```html
<pwa-install id="a2hs"></pwa-install>
<button
id="install"
onclick="document.getElementById('a2hs').prompt()"
>
Install
</button>
```
```css
#install {
visibility: hidden;
}
:has(#a2hs[is-install-available]) #install {
visibility: visible;
}
```
## Lit
```html
<pwa-install
id="a2hs"
@pwa-install-available="${this.handlePWAInstallAvailableEvent}"
@pwa-install-installing="${this.handlePWAInstallInstallingEvent}"
@pwa-install-installed="${this.handlePWAInstallInstalledEvent}"
@pwa-install-error="${this.handlePWAInstallErrorEvent}"
@is-install-supported-changed="${this.handleIsInstallSupportedPropertyChangedEvent}"
@is-install-available-changed="${this.handleIsInstallAvailablePropertyChangedEvent}"
@platforms-changed="${this.handlePlatformsPropertyChangedEvent}"
@choice-result-changed="${this.handleChoiceResultPropertyChangedEvent}"
@is-get-installed-related-apps-supported-changed="${this.handleIsGetInstalledRelatedAppsSupportedPropertyChangedEvent}"
@related-apps-changed="${this.handleRelatedAppsPropertyChangedEvent}"
>
</pwa-install>
```
```js
const pwaInstall = this.shadowRoot.getElementById('a2hs');
```
## Polymer
```html
<pwa-install
id="a2hs"
is-install-supported="{{isInstallSupportedPropertyValue}}"
is-install-available="{{isInstallAvailablePropertyValue}}"
platforms="{{platformsPropertyValue}}"
choice-result="{{choiceResultPropertyValue}}"
is-get-installed-related-apps-supported="{{isGetInstalledRelatedAppsSupportedPropertyValue}}"
related-apps="{{relatedAppsPropertyValue}}"
on-pwa-install-available="handlePWAInstallAvailableEvent"
on-pwa-install-installing="handlePWAInstallInstallingEvent"
on-pwa-install-installed="handlePWAInstallInstalledEvent"
on-pwa-install-error="handlePWAInstallErrorEvent"
on-is-install-supported-changed="handleIsInstallSupportedPropertyChangedEvent"
on-is-install-available-changed="handleIsInstallAvailablePropertyChangedEvent"
on-platforms-changed="handlePlatformsPropertyChangedEvent"
on-choice-result-changed="handleChoiceResultPropertyChangedEvent"
on-is-get-installed-related-apps-supported-changed="handleIsGetInstalledRelatedAppsSupportedPropertyChangedEvent"
on-related-apps-changed="handleRelatedAppsPropertyChangedEvent"
>
</pwa-install>
```
```js
const pwaInstall = this.$.a2hs;
```
### Use case
Property values can be used to show/hide and/or change the state of other HTML elements e.g. the UI for promoting PWA installation:
```html
<pwa-install
id="a2hs"
is-install-supported="{{isInstallSupportedPropertyValue}}"
is-install-available="{{isInstallAvailablePropertyValue}}"
>
</pwa-install>
<button
on-click="handleInstallButtonClickEvent"
hidden$="[[!isInstallSupportedPropertyValue]]"
disabled$="[[!isInstallAvailablePropertyValue]]"
>
Install
</button>
```
```js
handleInstallButtonClickEvent() {
this.$.a2hs.prompt();
}
```
# Customize
`PWAInstall` class can be imported without registering `<pwa-install>` custom HTML element. It can be used to register the web component with a different custom HTML element name:
```js
import { PWAInstall } from 'pwa-install/pwa-install-class.js';
customElements.define('your-custom-element-name', PWAInstall);
```
or customize the web component:
```js
import { PWAInstall } from 'pwa-install/pwa-install-class.js';
class YourCustomElement extends PWAInstall {
// Add or override methods, properties, attributes, events, etc.
}
customElements.define('your-custom-element-name', YourCustomElement);
```
```html
<your-custom-element-name id="a2hs"></your-custom-element-name>
```
# Further reading
[Patterns for promoting PWA installation](https://web.dev/articles/promote-install)
[Native app install prompt](https://developer.chrome.com/blog/app-install-banners-native)
[Is your app installed? `getInstalledRelatedApps()` will tell you!](https://web.dev/articles/get-installed-related-apps)
[Detect if your native app is installed from your web site](https://medium.com/dev-channel/detect-if-your-native-app-is-installed-from-your-web-site-2e690b7cb6fb)
[What does it take to be installable?](https://web.dev/articles/install-criteria)
[Add a web app manifest](https://web.dev/articles/add-manifest)