Introduction
As of 2021, PWA features are supported to varying degrees by Google Chrome, Apple Safari, Firefox for Android (not desktop), and Microsoft Edge. This means your PWA can be installed as an app on all modern mobiles and desktops.
This makes PWAs very powerful as a single code base can be used across variety of devices without the need for varied configurations to support different environments (looking at you flutter).
This article will show you how to solve the issue of adding an Add to Homescreen button to your PWA which can show the user a prompt to install your app when required.
This tutorial is using VueJS, but you can use the same code anywhere.
Problem
The Add to Homescreen popup shows up on page load rather than when required.
Solution
Capture the event, store it and show it as required.
Code
We make a component addToHomeBtn.vue
which is imported in the entry point of your app. App.vue
in this case.
Start by creating a variable to store the event, so it can be used later:
data(){
return {
deferredPrompt: null,
}
}
Now add the method to capture the event:
captureEvent() {
window.addEventListener('beforeinstallprompt', (e) => {
// Prevent Chrome 67 and earlier from automatically showing the prompt
e.preventDefault()
// Stash the event so it can be triggered later.
this.deferredPrompt = e
})
}
And now simply call this method in the mounted hook of the component.
mounted() {
this.captureEvent()
}
To re-invoke the prompt, simply use the event we stored before.
clickCallback() {
// Show the prompt
this.deferredPrompt.prompt()
// Wait for the user to respond to the prompt
this.deferredPrompt.userChoice.then((choiceResult) => {
if (choiceResult.outcome === 'accepted') {
// Add analyticcs event
this.$gtag.event('add_to_home_screen')
}
this.deferredPrompt = null
})
}
<button
v-if="deferredPrompt"
ref="addBtn"
class="add-button"
@click="clickCallback"
>
Add
</button>
And, that's done!
Full Component Code
<template>
<div>
<button
v-if="deferredPrompt"
ref="addBtn"
class="add-button"
@click="clickCallback"
>
Add
</button>
</div>
</template>
<script>
export default {
name: 'AddToHomeScreen',
data: () => ({
deferredPrompt: null,
}),
mounted() {
this.captureEvent()
},
methods: {
captureEvent() {
window.addEventListener('beforeinstallprompt', (e) => {
// ! Prevent Chrome 67 and earlier from automatically showing the prompt
e.preventDefault()
// Stash the event so it can be triggered later.
this.deferredPrompt = e
})
},
clickCallback() {
// Show the prompt
this.deferredPrompt.prompt()
// Wait for the user to respond to the prompt
this.deferredPrompt.userChoice.then((choiceResult) => {
if (choiceResult.outcome === 'accepted') {
// Call another function?
}
this.deferredPrompt = null
})
},
},
}
</script>
The primary part of the code is pure JS and can be used anywhere. Just make sure you call the event before browser shows the prompt.
Thanks for reading!
Top comments (1)
Thanks for the description.
Unfortunately, I got this:
_TypeError: Cannot read properties of null (reading 'prompt')
at Proxy.clickCallback (PWAPrompt.vue:43:27)
at runtime-dom.esm-bundler.js:296:60
at callWithErrorHandling (runtime-core.esm-bundler.js:158:18)
at callWithAsyncErrorHandling (runtime-core.esm-bundler.js:166:17)
at callWithAsyncErrorHandling (runtime-core.esm-bundler.js:176:17)
at HTMLButtonElement.invoker (runtime-dom.esm-bundler.js:278:5)
_
Any ideas?