Feature specifications for Web Application Manifest extensions & incubations which Chromium has shipped but do not have committments / implementations from other user agents. Instead of keeping these features as explainers, they are documented more officially here.

This is an unofficial proposal.

display_override member

For advanced usages, the display_override member can be used to specify a custom fallback order of display mode values for developers to choose their preferred display mode.

The display_override member of the [=application manifest=] is a sequence of display mode values. This item represents the developer's preferred fallback chain for display modes. This field overrides the [=manifest/display=] member. If the user agent does not support any of the display modes specified here, then it falls back to considering the [=manifest/display=] member. See display modes for the algorithm steps.

The following steps are added to the [=application manifest/processing extension-point=] in determining the web app's chosen display mode:

  1. [=list/For each=] |candidate_display_mode:DisplayModeType| of |manifest|.{{display_override}}:
    1. If the user agent supports the |candidate_display_mode|, then return |candidate_display_mode|.

This member is intended to be only used for advanced cases, where the developer wants explicit control over the fallback order of their display modes. Otherwise, the [=manifest/display=] member is sufficient for most use cases.

Usage Example

The following shows a [=manifest=] that prefers the minimal-ui display mode over standalone, but if minimal-ui isn't supported, falls back to standalone as opposed to browser.

          {
            "name": "Recipe Zone",
            "description": "All of the recipes!",
            "icons": [{
              "src": "icon/hd_hi",
              "sizes": "128x128"
            }],
            "start_url": "/index.html",
            "display_override": ["minimal-ui"],
            "display": "standalone",
            "theme_color": "yellow",
            "background_color": "red"
          }
        

`share_target` member

The `share_target` member registers a web application as "target" for share actions (e.g., for sharing a text, a URL, or a file). The `share_target` member is part of the [[[web-share-target]]] specification.

note_taking member

The `note_taking` member of the Web Application Manifest is an object that contains information related to note-taking. It has the following members:

A user agent MAY use these members to treat the web application differently as an application with note-taking capabilities (e.g., integrate with operating system note-taking surfaces).

new_note_url member

The [=note_taking=] `new_note_url` member is a [=string=] that represents the URL the developer would prefer the user agent load when the user wants to take a new note using the web application (e.g., from an operating system shortcut icon or keyboard shortcut).

The `new_note_url` member is purely advisory, and a user agent MAY ignore it or provide the end-user the choice of whether to use it. The user agent MAY provide the end-user the choice to modify it.

Usage Example

The following shows a [=manifest=] for a note-taking application.

          {
            "name": "My Note Taking App",
            "description": "You can take notes!",
            "icons": [{
              "src": "icon/hd_hi",
              "sizes": "128x128"
            }],
            "start_url": "/index.html",
            "display": "standalone",
            "note_taking": {
              "new_note_url": "/new_note.html"
            }
          }
        

Processing the `note_taking` member

To process the `note_taking` member, given [=ordered map=] |json:ordered map|, [=ordered map=] |manifest:ordered map|, [=URL=] |manifest_URL:URL|, run the following during the extension point in [=processing a manifest=]:

  1. If |json|["note_taking"] does not [=map/exist=], return.
  2. If the type of |json|["note_taking"] is not [=ordered map=], return.
  3. Set |manifest|["note_taking"] to a new [=ordered map=].
  4. [=process the `new_note_url` member=] passing |json|["note_taking"], |manifest|["note_taking"], and |manifest URL|.

Processing the `new_note_url` member

To process the `new_note_url` member, given [=ordered map=] |json_note_taking:ordered map|, [=ordered map=] |manifest_note_taking:ordered map|, [=URL=] |manifest_URL:URL|, run the following:

  1. If |json_note_taking|["new_note_url"] does not [=map/exist=], return.
  2. If the type of |json_note_taking|["new_note_url"] is not [=string=], return.
  3. Let |new_note_url:URL| be the result of [=URL Parser|parsing=] |json_note_taking|["new_note_url"] with |manifest URL| as the base URL.
  4. If |new_note_url| is failure, return.
  5. If |new_note_url| is not [=manifest/within scope=] of |manifest URL|, return.
  6. Set manifest_note_taking["new_note_url"] to |new_note_url|.

Launching the `new_note_url`

To launch the `new_note_url`, given processed manifest |manifest:processed manifest|, run the following steps:

  1. If |manifest|["note_taking"] does not [=map/exist=], return.
  2. If |manifest|["note_taking"]["new_note_url"] does not [=map/exist=], return.
  3. If the type of |manifest|["note_taking"]["new_note_url"] is not [=URL=], return.
  4. Let |browsing context:Browsing Context| be the result of creating a new [=top-level browsing context=].
  5. [=Navigate=] |browsing context| to resource |manifest|["note_taking"]["new_note_url"].

Installation prompts

There are multiple ways that the installation process can be triggered:

In any case, the user agent MUST NOT present an install prompt if the document is not installable.

The user agent MAY, at any time (only if the document is installable), run the steps to notify that an install prompt is available at any time, giving the site the opportunity to show a site-triggered install prompt without the user needing to interact with the user agent UI.

To present an install prompt:

  1. Show some user-agent-specific UI, asking the user whether to proceed with installing the app. The result of this choice is either {{AppBannerPromptOutcome/"accepted"}} or {{AppBannerPromptOutcome/"dismissed"}}.
  2. Return result, and in parallel:
    1. If result is {{AppBannerPromptOutcome/"accepted"}}, run the steps to install the web application.

The steps to notify that an install prompt is available are given by the following algorithm:

  1. Wait until the {{Document}} of the top-level browsing context is completely loaded.
  2. If there is already an install prompt being presented or if the steps to install the web application are currently being executed, then abort this step.
  3. Queue a task on the application life-cycle task source to do the following:
    1. Let |mayShowPrompt| be the result of [=fire an event=] named `"beforeinstallprompt"` at the [=top-level browsing context=]'s [=relevant global object=] using the {{BeforeInstallPromptEvent}} interface, with steps to initialize the {{Event/cancelable}} attribute to `true`.
    2. If |mayShowPrompt| is true, then the user agent MAY, in parallel, request to present an install prompt with |event|.

Installable web applications

Installation process

The steps to install the web application are given by the following algorithm:

  1. Let manifest be the manifest of an installable document.
  2. Perform an unspecified sequence of actions to attempt to register the web application in the user's operating system (e.g., create shortcuts that launch the web application, register the application in the system uninstall menu, etc.). If the installation fails (which can be for any reason, for example, the OS denying permission to the user agent to add an icon to the home screen of the device), abort these steps.
  3. Queue a task on the application life-cycle task source to fire an event named `"appinstalled"` at the [=top-level browsing context=]'s [=relevant global object=] for which the installation took place.

Installability signals

By design, this specification does not provide developers with an explicit API to "install" a web application. Instead, a manifest can serve as an installability signal to a user agent that a web application can be installed.

Examples of installability signals for a web application:

This list is not exhaustive and some installability signals might not apply to all user agents. How a user agent makes use of these installability signals to determine if a web application can be installed is left to implementers.

Installation Events

[=event|Events=] of this specification rely on the application life-cycle task source.

BeforeInstallPromptEvent Interface

The beforeinstallprompt event is somewhat misnamed, as it does not necessarily signal that a manual installation will follow (depending on the user agent, it might just be giving the site the ability to trigger an install prompt). It is so named for historical reasons.
          [Exposed=Window]
          interface BeforeInstallPromptEvent : Event {
            constructor(DOMString type, optional EventInit eventInitDict = {});
            Promise<PromptResponseObject> prompt();
          };

          dictionary PromptResponseObject {
            AppBannerPromptOutcome userChoice;
          };

          enum AppBannerPromptOutcome {
            "accepted",
            "dismissed"
          };
        

The {{BeforeInstallPromptEvent}} is dispatched when the site is allowed to present a site-triggered install prompt, or prior to the user agent presenting an automated install prompt. It allows the site to cancel the automated install prompt, as well as manually present the site-triggered install prompt.

If the {{BeforeInstallPromptEvent}} is not cancelled, the user agent is allowed to present an install prompt (specifically, an automated install prompt) to the end-user. Canceling the default action (via {{Event/preventDefault()}}) prevents the user agent from presenting an install prompt. The user agent is free to run steps to notify that an install prompt is available again at a later time.

The PromptResponseObject contains the result of calling {{BeforeInstallPromptEvent/prompt()}}. It contains one member, userChoice, which states the user's chosen outcome.

An instance of a {{BeforeInstallPromptEvent}} has the following internal slots:

[[\didPrompt]]
A boolean, initially `false`. Represents whether this event was used to present an install prompt to the end-user.
[[\userResponsePromise]]
A promise that represents the outcome of presenting an install prompt.

prompt() method

The prompt method, when called, runs the following steps:

  1. Let |userResponsePromise| be {{BeforeInstallPromptEvent/[[userResponsePromise]]}}.
  2. If |userResponsePromise| is pending:
    1. If [=this=].{{BeforeInstallPromptEvent/[[didPrompt]]}} is `true`, terminate this algorithm.
    2. If this event's {{Event/isTrusted}} attribute is `false`, reject |userResponsePromise| with {{"NotAllowedError"}} and terminate this algorithm.
    3. Set [=this=].{{BeforeInstallPromptEvent/[[didPrompt]]}} to `true`.
    4. In parallel, request to present an install prompt with [=this=]. Wait, possibly indefinitely, for the end-user to make a choice.
  3. Return |userResponsePromise|.

To request to present an install prompt with {{BeforeInstallPromptEvent}} event:

  1. Present an install prompt and let |outcome| be the result.
  2. Let |response| be a newly created {{PromptResponseObject}}, initializing its {{PromptResponseObject/userChoice}} to |outcome|.
  3. [=Resolve=] |event|.{{BeforeInstallPromptEvent/[[userResponsePromise]]}} with |response|.

Usage example

This example shows how one might prevent an automated install prompt from showing until the user clicks a button to show a site-triggered install prompt. In this way, the site can leave installation at the user's discretion (rather than prompting at an arbitrary time), whilst still providing a prominent UI to do so.

              window.addEventListener("beforeinstallprompt", event => {
                // Suppress automatic prompting.
                event.preventDefault();

                // Show the (disabled-by-default) install button. This button
                // resolves the installButtonClicked promise when clicked.
                installButton.disabled = false;

                // Wait for the user to click the button.
                installButton.addEventListener("click", async e => {
                  // The prompt() method can only be used once.
                  installButton.disabled = true;

                  // Show the prompt.
                  const { userChoice } = await event.prompt();
                  console.info(`user choice was: ${userChoice}`);
                });
              });
            

AppBannerPromptOutcome enum

The AppBannerPromptOutcome enum's values represent the outcomes from presenting an install prompt.

"accepted":
The end-user indicated that they would like the user agent to install the web application.
"dismissed":
The end-user dismissed the install prompt.

Extensions to the `Window` object

          partial interface Window {
            attribute EventHandler onappinstalled;
            attribute EventHandler onbeforeinstallprompt;
          };
        

onappinstalled attribute

The onappinstalled event handler IDL attribute handles "appinstalled" events.

onbeforeinstallprompt attribute

The onbeforeinstallprompt event handler IDL attribute handles "beforeinstallprompt" events.