Skip to content

Feedback

InstallPrompt

A dismissible banner that offers to install the app, with the native dialog on Chromium and Share-sheet steps on iOS.

<script>
  import { InstallPrompt } from "@codeatlasdev/ui";
</script>

<InstallPrompt onchoice={(outcome) => console.log(outcome)} />

Render it once, in the root layout. It shows nothing until there is something to offer:

  • Chromium (Android, desktop): it keeps the beforeinstallprompt event, so the browser’s own mini-infobar does not appear, and shows an Install button that opens the native dialog. The browser only fires the event when the app is installable: a manifest with display: "standalone" and 192 and 512 icons, and a service worker (see PWA).
  • iOS Safari (iPhone, and iPad, which reports a Mac user agent): Safari has no install API, so it shows the two steps, Share then Add to Home Screen.
  • Already installed (display-mode: standalone, or navigator.standalone): nothing.
  • Dismissed: nothing for dismissDays, remembered in localStorage.
#244

Native prompt

The Chromium flow: Install opens the browser's install dialog. This demo fires a stand-in event so the banner shows in any browser.

Reference #244 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { InstallPrompt } from '@codeatlasdev/ui';
  import { onMount } from 'svelte';

  // A real page waits for the browser's `beforeinstallprompt`. This demo fires a stand-in so the
  // banner can be seen anywhere; Install then resolves without opening a browser dialog.
  onMount(() => {
    const event = new Event('beforeinstallprompt', { cancelable: true });
    Object.assign(event, {
      prompt: () => Promise.resolve(),
      userChoice: Promise.resolve({ outcome: 'dismissed' }),
    });
    dispatchEvent(event);
  });
</script>

<!-- The prompt renders nothing until it is mounted in the browser; the box gives the island
     something to intersect (client:visible) and keeps the page from shifting when it appears. -->
<div class="stage">
  <InstallPrompt mode="native" storageKey="demo-install-native" />
</div>

<style>
  .stage { min-height: calc(var(--ca-space-8) * 3); }
</style>
#243

iOS instructions

What Safari on iPhone and iPad gets: the two steps, no button.

Reference #243 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { InstallPrompt } from '@codeatlasdev/ui';
</script>

<!-- The prompt renders nothing until it is mounted in the browser; the box gives the island
     something to intersect (client:visible) and keeps the page from shifting when it appears. -->
<div class="stage">
  <InstallPrompt mode="ios" storageKey="demo-install-ios" />
</div>

<style>
  .stage { min-height: calc(var(--ca-space-8) * 3); }
</style>

Props

PropTypeDefaultDescription
mode'auto' | 'native' | 'ios''auto'`auto` picks from the browser. Force `native` or `ios` to document or test one flow.
dismissDaysnumber14Days the banner stays hidden after the user closes it.
storageKeystring'ca-install-dismissed'`localStorage` key that holds the end of the dismissal.
onchoice(outcome: 'accepted' | 'dismissed') => void–The user's answer in the browser's install dialog.
ondismiss() => void–The user closed the banner with the close button.
classstring''Extra CSS classes.

Strings come from the installPrompt group of the i18n catalog (en and pt-BR built in).