Make a web app installable in a breeze
Tags: webdev, javascript, programming, tutorial
Published: 2023-11-13 22:48:47

---
title: Make a web app installable in a breeze
published: true
description: Using the install modal web component by Store.app to encourage users to install you web app into their home screens.
tags: webdev,javascript,programming,tutorial
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yr4v6m658la11kah1f99.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2023-11-01 14:21 +0000
---

Welcome to this tutorial on making your web app installable in a few simple steps.

## Summary

- [What is a progressive web app?](#what-is-a-progressive-web-app)
- [Defining a web app manifest](#defining-a-web-manifest)
- [Registering a service worker](#registering-a-service-worker)
- [Show an install button](#show-an-install-button)
- [Conclusion](#conclusion)

## What is a progressive web app?

For a web app to be considered installable, a Progressive Web App ([PWA](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps)), it must adhere to several criteria:

- It must define a [manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest) describing how the app behaves and interacts with the UI.
- It should register a [Service Worker](https://developer.mozilla.org/fr/docs/Web/API/Service_Worker_API) to enable offline browsing.
- It needs to have a responsive design suitable for small devices.

Other secondary criteria exist, but we'll focus on the essential information here.

## Defining a web manifest

Start by adding a "manifest.json" file to your project's root:

```json
{
  "name": "Dev.to",
  "short_name": "DEV",
  "start_url": "/",
  "display": "standalone",
  "icons": [
    {
      "src": "images/touch/homescreen48.png",
      "sizes": "48x48",
      "type": "image/png"
    }
}
```

- The "start_url" determines the URL shown when launching the app.
- The "display" specifies how the browser renders the UI when launching the app.

Refer to the [manifest MDN documentation](https://developer.mozilla.org/en-US/docs/Web/Manifest) for a comprehensive list of configuration options..

Include the manifest file in your HTML:

```html
<!DOCTYPE html>
<html>
  <head>
    <!-- ... !-->
    <link rel="manifest" href="manifest.json" />
  </head>
  <body>
    <!-- ... -->
  </body>
</html>
```

## Registering a service worker

[Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) introduce powerful caching patterns for fine-grained control over how the browser handles requests. Let's implement the simple [Network First](https://developer.chrome.com/docs/workbox/caching-strategies-overview/#network-first-falling-back-to-cache) pattern using [Workbox.js](https://developer.chrome.com/docs/workbox/).

This pattern tells the browser:

> If you encounter a resource, wether it be an image, an HTML document, or anything, if the connectivity is on, grab the content of the resource from the server and store it in the cache. 
>
> If the network is off, and the resource is present in the cache, grab it from there, else behave like usual.

You can learn more on all the various caching strategies on the [Workbox.js](https://developer.chrome.com/docs/workbox/) documentation about [caching strategies](https://developer.chrome.com/docs/workbox/caching-strategies-overview/).

Install the library:

```bash
npm install workbox-core workbox-routing workbox-strategies
```

Create a "service-worker.js" file:

```ts
const { clientsClaim } = require("workbox-core");
const { registerRoute } = require("workbox-routing");
const { NetworkFirst } = require("workbox-strategies");

clientsClaim();

registerRoute(
    /.*/u,
    new NetworkFirst({
        cacheName: "nf-v1",
    })
);
```

Update the "app.js" entry point to start the service worker:

```ts
if (navigator.serviceWorker instanceof ServiceWorkerContainer) {
    navigator.serviceWorker.register("/service-worker.js", { scope: "/" });
}
```

Include the script in your HTML:

```html
<!DOCTYPE html>
<html>
  <head>
    <!-- ... !-->
    <link rel="manifest" href="manifest.json" />
  </head>
  <body>
    <!-- ... -->
    <script type="text/javascript" src="app.js"></script>
  </body>
</html>
```

## Show an install button

To make your web app more discoverable, register it on [Store.app](https://store.app). This platform can increase your app's visibility, and they provide a convenient install modal.

{% embed https://dev.to/anwar_nairi/an-app-store-for-web-apps-5fo2 %}

Install the NPM package:

```bash
npm install @storedotapp/pwa-install-dialog
```

Import the code in your main entry javascript file:

```ts
require("@storedotapp/pwa-install-dialog");

if (navigator.serviceWorker instanceof ServiceWorkerContainer) {
    navigator.serviceWorker.register("/service-worker.js", { scope: "/" });
}
```

Add a button to your HTML for users to install the app:

```html
<!DOCTYPE html>
<html>
  <head>
    <!-- ... !-->
    <link rel="manifest" href="manifest.json" />
  </head>
  <body>
    <button id="install-button">Install the app</button>    

    <pwa-install-dialog id="install-dialog" app="fitness-app" theme="dark"></pwa-install-dialog>

    <script type="text/javascript" src="app.js"></script>
  </body>
</html>
```

Register an "onClick" listener to show the modal when clicking the button:

```ts
require("@storedotapp/pwa-install-dialog");

if (navigator.serviceWorker instanceof ServiceWorkerContainer) {
    navigator.serviceWorker.register("/service-worker.js", { scope: "/" });
}

document.addEventListener("DOMContentLoaded", () => {
  const button = document.getElementById("install-button");

  if (button instanceof HTMLButtonElement) {
    button.addEventListener("click", () => {
      const dialog = document.getElementById("install-dialog");

      if (dialog instanceof HTMLElement) {
        dialog.show();
      }
    });
  }
});
```

## Conclusion

In just a few lines of code, we've transformed a website or web app into an installable web app. The evolution of the web into a platform with capabilities rivaling native apps is truly fascinating.

Installable web apps are shaping the future for a seamless, unified experience across all devices, offering lightweight, capable, and rich applications.

One limitation with the actual setup is that our app will still display the "install the app" button even if the app is installed (e.g. displayed as a standalone app).

Let us improve it by hiding the button if the app is already installed.

Create an "app.css" file with the following code:

```css
@media all and (display-mode: standalone) {
  #install-button {
    display: none;
  }
}
```

Now, only users who haven't installed your app will see the install button.

You can see this in action as I implemented it on [Predzo](https://predzo.com).

I hope this tutorial has helped you understand PWAs better and demonstrated how easy it is to create an outstanding offline-ready installable web experience.

Happy web building!

Cover image by [Roberto Nickson](https://www.pexels.com/@rpnickson/) from [Pexels](https://www.pexels.com/).