Feature specifications for Web Application Manifest extensions & incubations which Chromium has shipped but do not have commitments / 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 [=manifest/display_override=] member can be used to specify a custom fallback order of display mode list values for developers to choose their preferred display mode for the web application.
The [=manifest/display_override=] member of the [=application manifest=] is a [=list=] of [=display override entries=]. A display override entry is either a display modes list value (including [=display mode extensions|extensions=] like [=display mode/window-controls-overlay=], [=display mode/tabbed=], and [=display mode/unframed=]) or a [=DisplayOverrideEntryObject=].
This member 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 processing the display members for the algorithm steps.
A DisplayOverrideEntryObject is an [=ordered map=] with the following members:
The following steps are added to the [=application manifest/processing extension-point=] in determining the web app's chosen display mode, which now also takes an optional [=URL=] |document URL|:
To process the `display_override` member, given [=ordered map=] |json:ordered map|, [=ordered map=] |manifest:ordered map|, and [=URL=] |manifest URL:URL|, run the following:
Additionally to the normal display modes, [=manifest/display_override=] also supports certain display mode extensions.
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"
}
unframed display mode
The [=display mode/unframed=] display mode enables [[[isolated-web-apps]]] to have full control over the appearance of the app window, including the title bar area.
A window in [=display mode/unframed=] does not have any host-native title bar or [=window controls=] visible, and the web contents are extended to the whole window area. The app can specify [=draggable regions=] in the web contents to create a customized title bar.
[=User agents=] MUST restrict the use of [=display mode/unframed=] to [[[isolated-web-apps]]].
Once an [=display mode/unframed=] window has been created, its display mode is fixed for the lifetime of the window. The [=user agent=] MUST NOT allow navigation to out-of-scope URLs to take place within the unframed window.
The following figures illustrate the visual difference between a standard web application window and one utilizing the [=display mode/unframed=] display mode. The regular app window (left) includes the host-native title bar and standard window controls. In contrast, the unframed app window (right) removes these host-provided frame decorations, allowing the web contents to occupy the entire window area.
The [=display mode/unframed=] display mode can be queried using the `display-mode` media feature.
@media (display-mode: unframed) {
/* styles for unframed mode */
}
Giving developers control of the title bar enables them to spoof content in what was previously a trusted, user agent-controlled region. To mitigate this threat, the feature must only be available for [[[isolated-web-apps]]] and gated behind a window management permission.
Since there is no title bar in [=display mode/unframed=] windows, important indicators like the app origin or privacy indicators (e.g., for camera and microphone access) that the [=user agent=] normally displays in the title bar will need to be shown elsewhere. The specific location to display those indicators is platform dependent and to be decided by the user agent.
The `app-region` property can be used to define with CSS which regions or elements in for example a title bar are draggable.
The `app-region` property MUST only take effect when the applied [=display mode=] of the window is [=display mode/unframed=] or [=display mode/window-controls-overlay=].
To facilitate all of the new extension and incubation features added by this specification, the user agent SHOULD run the following during the extension point in [=processing a manifest=] (having access to [=URL=] |document URL:URL|, [=URL=] |manifest URL:URL|, [=ordered map=] |json:ordered map|, and [=ordered map=] |manifest:ordered map|):
tab_strip member
The `tab_strip` member of the Web Application Manifest is an object that contains information about how the application is intended to behave in the [=display mode/tabbed=] display mode. It has the following members:
home_tab member
The `home_tab` member of the [=tab_strip=] object is an ordered map that contains information about a special "home tab" that is intended to serve as the top-level menu for the application. It contains the following members:
The scope_patterns member is a list of
{{URLPatternInput}}s that define the [=within home tab scope|scope of
the home tab=] relative to the [=manifest URL=].
An application has a home tab if the applied [=display mode=] of the application is [=display mode/tabbed=], and the [=Document/processed manifest=] includes a non-null [=home_tab=] member of the [=tab_strip=] member.
The home tab context is an optional [=application context=] that has special properties compared to other application contexts. If the application [=has a home tab=], every application window SHOULD feature a [=home tab context=]. If not, then the application windows SHOULD NOT have a [=home tab context=].
How the [=home tab context=] is presented is at the discretion of the user agent, but it SHOULD have a different appearance to normal application contexts.
A [=URL=] |url:URL| is said to be within home tab scope if and only if:
A URL is is outside of home tab scope if it is not [=within home tab scope=].
If the application [=has a home tab=], whenever a new application window is created (for example when launching the application, or when moving a tab to a new window), the user agent MUST create a new [=home tab context=] in that window. A newly created [=home tab context=] SHOULD be navigated to the [=start URL=], which by definition is [=within home tab scope=].
When [=navigate|navigating=] the [=top-level traversable=] associated with a [=home tab context=] to a [=URL=] |url:URL| that is [=outside of home tab scope=], the following steps are run:
"_blank" and noopener true.
When [=navigate|navigating=] a [=top-level traversable=] with a [=display mode=] of [=display mode/tabbed=] that is not associated with a [=home tab context=] (i.e. a non-home tab) to a [=URL=] |url:URL| that is [=within home tab scope=], the following steps are run:
The above rules are intended to ensure that the following invariants are always true, for applications that [=has a home tab|have a home tab=]:
User agents will not dynamically move documents between home-tab and non-home-tab contexts if they change their [=URL/fragment=], or use the {{History}} API to modify their display URL into or out of the home tab scope, because no navigation is taking place. For this reason, the above invariants only care about the [=Document/URLs=] that documents had at the time of their creation.
For single-page applications that "pretend" to navigate by modifying their URLs, this may result in undesirable behaviour that breaks the above invariants (e.g. if the user clicks a link from the home tab to dynamically change the URL to a non-home page, they will stay inside the home tab because it is not actually navigating). To avoid this situation, the application can detect when it is in tabbed application mode and change its behavior to perform actual navigations into and out of the home tab scope, rather than modifying the URL.
new_tab_button member
The [=tab_strip/new_tab_button=] member is an ordered map that describes the behaviour of a UI affordance (such as a button) which, when clicked/activated, opens a new [=application context=] within the application window. It has the following members:
The url member
is a string that represents a URL relative to the [=manifest URL=]
that is [=manifest/within scope=] of a [=Document/processed
manifest=].
An application has a new tab button if the [=Document/processed manifest=]'s [=new_tab_button=]'s [=new_tab_button/url=] member is [=outside of home tab scope=]. If the application does not [=has a new tab button|have a new tab button=], the user agent SHOULD NOT make the "new tab" affordance available to the end user.
When the new tab button is activated by the end user, the following steps are run:
To process the `tab_strip` member, given [=ordered map=] |json:ordered map|, [=ordered map=] |manifest:ordered map|, and [=URL=] |manifest URL:URL|, run the following during the extension point in [=processing a manifest=]:
To process the `home_tab` member, given [=ordered map=] |json tab strip:ordered map|, [=ordered map=] |manifest tab strip:ordered map|, and [=URL=] |manifest URL:URL|, run the following:
To process the `new_tab_button` member, given [=ordered map=] |json tab strip:ordered map|, [=ordered map=] |manifest tab strip:ordered map|, [=URL=] |manifest URL:URL|, and [=URL=] |start URL:URL|, run the following:
To process the `scope_patterns` member, given [=ordered map=] |json home tab:ordered map|, [=ordered map=] |manifest home tab:ordered map| and [=URL=] |manifest URL:URL|, run the following:
{
"name": "Tabbed App Example",
"start_url": "/",
"display": "standalone",
"display_override": ["tabbed"],
"tab_strip": {
"home_tab": {
"scope_patterns": [
{"pathname": "/"},
{"pathname": "/index.html"}
]
},
"new_tab_button": {
"url": "/create"
}
}
}
This example is a tabbed web app that falls back to a single-document
standalone window if tabbed mode is not supported. Any navigation to
the main index page (either / or
/index.html) is opened in the [=home tab context=]. The
new tab button will open a new tab at /create.
Note that the [=URL/query=] part of the URL is ignored by default
when matching against [=tab_strip/home_tab/scope_patterns=] (so a
navigation to /index.html?utm_source=foo will open in
the home tab). However, when matching against [=start URL=], the
[=URL/query=] must match exactly, so sites that want to ignore the
query are advised to explicitly include the [=start URL=]'s
[=URL/path=] as a scope pattern.
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.
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"
}
}
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=]:
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:
To launch the `new_note_url`, given processed manifest |manifest:processed manifest|, run the following steps:
The user agent MAY [=launch the `new_note_url`=] for a given [=installed web application=] at any time, typically in response to a user affordance.
The [=manifest=]'s protocol_handlers member is an array of
protocol handler descriptions that allows a web application to
handle URL protocols.
On installation, a user agent SHOULD register protocol handlers with the Operating System via interactions that are consistent with:
To process the `protocol_handlers` member, given [=object=] |json:JSON|, |manifest:ordered map|:
A user agent SHOULD ask users for permission before registering a [=protocol handler description=] protocol_handlers as the default handler for a protocol with the host operating system. A user agent MAY truncate the list of [=protocol handler description=] protocol_handlers presented in order to remain consistent with the conventions or limitations of the host operating system.
Each protocol handler description is an [=object=] that represents a protocol that the web application wants to handle, corresponding to the [=manifest/protocol_handlers=] member. It has the following members:
A user agent SHOULD use these values to register the web application as a handler with the operating system. When the user activates a protocol handler URL, the user agent SHOULD run handling a protocol launch.
The protocol member of a
protocol handler description is a string that
represents the protocol to be handled, such as `mailto` or
`web+auth`.
The [=protocol handler description/protocol=] member of a
protocol handler description is equivalent to
{{NavigatorContentUtils/registerProtocolHandler()}}'s
scheme argument defined in [[HTML]].
The url member of a
protocol handler description is the URL
[=manifest/within scope=] of the application that opens when the
associated protocol is activated.
The [=protocol handler description/url=] member of a protocol
handler description is equivalent to
{{NavigatorContentUtils/registerProtocolHandler()}}'s
url argument defined in [[HTML]].
When a protocol handler description protocol_handler having [=manifest=] manifest is invoked, it goes through the same steps used to [=invoke a protocol handler=] where the user agent, instead of [=navigating=] to resultURL, SHOULD [=launch a web application=] passing manifest and resultURL.
This should not invoke and alter [=invoke a protocol handler=] in this way. The computation of resultURL should be extracted out into a separate algorithm for general use.
Depending on the operating system capabilities, the protocol handler could become a 'default' handler (e.g. handling launches of a given protocol automatically) of a given protocol without the explicit knowledge of the user. To protect against possible misuse, user agents MAY employ protections such as:
If a user agent removes the the registration of the protocol handler entity it SHOULD provide UX for the user to re-register the web app and protocol with the operating system.
The [=manifest=]'s file_handlers member is a [=list=] that
provides instructions for how the app handles file-opening actions that
originate outside of the app itself.
The management, presentation, and selection of registered file-handling applications is at the discretion of the operating system.
To process the `file_handlers` member, given [=ordered map=] |json:ordered map|, [=ordered map=] |manifest:ordered map|, [=URL=] |manifest_url:URL|:
On [=installation=], a user agent SHOULD run the process to [=register file handlers=].
Each file handler represents a URL in the scope of the application that can handle launches with [=file types=] it accepts. It has the following members:
A user agent can use these members to associate the web application with [=file type=] on the operating system.
A file type can be defined by a [=MIME type=] and/or [=file extension=]. A file belongs to a file type if the OS determines it to have a [=MIME type=] and/or its name ends with a certain [=file extension=]. A file extension is a string that start with a "." and only contains valid suffix code points. Additionally, [=file extensions=] are limited to a length of 16 code points.
The [=file handler=]'s action member is a string that
represents a URL relative to the manifest URL that is
[=manifest/within scope=] of a processed manifest . This
URL will be navigated to in the steps to [=execute a file handler
launch=].
The [=file handler=]'s name member is a string that
identifies the file type to the user. [=User agents=] MAY pass this
information to the operating system during file handler
registration.
The file handler's icons member lists icons that serve as
graphical representations of a [=file type=]. User agents MAY pass
this information to the operating system during file handler
registration.
The [=file handler=]'s accept member is a dictionary
mapping [=MIME types=] to a list of [=file extensions=].
[=User agents=] MUST enforce that the [=file handler/accept=] entry only applies to files that have a matching extension.
In order to [=register file handlers=], some operating systems require [=MIME types=] and some require [=file extensions=]. Thus the manifest MUST always provide both for each [=file handler/accept=] entry.
In addition to complete [=MIME types=], "*" can be
used as the subtype of a [=MIME type=] to match, for example, all
image formats with "image/*" (that also apply to the
provided list of [=file extensions=]).
The [=file handler=]'s launch_type member is a string
that determines how the app is launched for files routed to this
handler. The possible values are `"single-client"` and
`"multiple-clients"`. If not provided, it defaults to
`"single-client"`.
When a [=file handler=] is determined to match a set of files, the [=user agent=] SHOULD use [=file handler/launch_type=] to control whether the app is launched once for each file (`"multiple-clients"`), or one time for all files (`"single-client"`). See {{LaunchParams/files}}. The user agent MUST NOT coalesce files from different [=file handlers=] into a single launch event.
To process a file handler item, given [=ordered map=] |item:ordered map|, [=URL=] |start_url:URL|, [=URL=] |scope:URL|, and [=URL=] |manifest URL:URL|:
The steps to execute a file handler launch are given by the following algorithm. The algorithm takes [=list=] |files:list| and a [=ordered map=] |manifest:ordered_map| which holds results from [=processing a manifest=].
A user agent SHOULD register file handlers with the host operating system, consistent with:
A user agent MAY truncate the total set of [=file extensions=] to preserve functionality and prevent abuse. A user agent MAY prevent associations with certain filetypes.
Depending on the operating system capabilities, the [=file handler=] could become a default handler of a given [=file type=] without the explicit knowledge of the user, handling launches of a given file type automatically. To protect against possible mis-use, [=user agents=] MAY require explicit user consent to begin with the process to [=execute a file handler launch=]. If consent is sought, the user agent SHOULD allow the user to specify that the decision is permanent and if so specified SHOULD remove the web application's OS registration as a file handling entity.
The name and icon of each file handler can be sensitive to privacy and security, as there isn't a specified way for the user to see and confirm these. Due to this, [=user agents=] MAY choose to ignore these in favor of alternative strings and icons or fall back on OS defaults.
In the following example, the web application has 3 different file handlers.
A related application is an application accessible to the underlying application platform that has a relationship with the web application.
The [=manifest=]'s related_applications member lists related
applications and serves as an indication of such a relationship
between web application and related applications. This
relationship is unidirectional and unless a listed application claims
the same relationship, the user agent MUST NOT assume a
bi-directional endorsement.
Example of usages of the `related_applications` could be a crawler that would use that information to gather more information about the web application or a browser that could suggest a listed application as an alternative if the user wants to install the web application.
To process the `related_applications` member, given [=ordered map=] |json:ordered map| and [=ordered map=] |manifest:ordered map|:
The [=manifest=]'s `prefer_related_applications` member is a
[=boolean=] that is used as a hint for the user agent to say that
related applications should be preferred over the web
application. If the `prefer_related_applications` member is set to
`true`, and the user agent wants to suggest to install the web
application, the user agent might want to suggest installing one of the
related applications instead.
The [=manifest=]'s scope_extensions member represents a list of an
application's desired [=scope extensions=].
A scope extension extends the [=manifest/navigation scope of a manifest=] by describing additional [=URLs=] that should be treated as being [=within extended scope=].
The user agent MUST [=process the scope_extensions member=] and [=validate scope extensions=] before it can [=apply extended scope=] to allow additional [=URLs=] to be [=within extended scope=].
A [=URL=] |target:URL| is within extended scope of a |manifest:processed manifest| if the |target| is [=manifest/within scope=] of the manifest or [=matches a validated scope extension=].
A [=URL=] |target:URL| matches a validated scope extension if the following algorithm returns `true`, given [=URL=] |target:URL| and [=list=] |validated_scope_extensions:list|:
The following example shows a [=manifest=] for an application which uses the `scope_extensions` member.
{
"id": "https://example.com/app",
"name": "My App",
"icons": [{
"src": "icon/hd_hi",
"sizes": "128x128"
}],
"start_url": "/app/index.html",
"scope": "/app",
"display": "standalone",
"scope_extensions": [
{ "type": "origin", "origin": "https://example.co.uk" },
{ "type": "origin", "origin": "https://help.example.com" }]
}
The following shows 2 [=web-app-origin-association=] files which can be downloaded from the `.well-known` path of the [=origins=] listed in the `scope_extensions` member.
{
"https://example.com/app": {
"scope": "/app"
}
}
{
"https://example.com/app": {
"scope": "/"
}
}
The navigation scope of this app consists of URLs that are [=URL/within scope=] of any of these [=URLs=]: `https://example.com/app`, `https://example.co.uk/app`, and `https://help.example.com`.
To process the `scope_extensions` member, given [=ordered map=] |json:ordered map|, [=ordered map=] |manifest:ordered map|, and [=URL=] |manifest_id:URL|:
To validate scope extensions, given [=ordered map=] |extension:ordered map| and [=URL=] |manifest_id:URL|:
The user agent MAY choose to apply apply extended scope in some scenarios and [=manifest/scope=] in others.
If the [=application context=]'s [=navigable/active document=]'s [=URL=] is not [=manifest/within scope=] but is [=within extended scope=], the user agent SHOULD provide UI that allows the user to determine the [=URL=] or at least its [=origin=], including whether it is served over a secure connection. This UI SHOULD differ from any UI used when the [=URL=] is not [=manifest/within scope=] of the [=application context=]'s [=Document/processed manifest=], in order to make it obvious that the user is still navigating the intended contents of the application but also keep the user informed of the privacy and security implications of navigating to a different [=origin=].
A web-app-origin-association file is a JSON file that can be used to [=validate scope extensions=] or [=validate origin migration=]. It confirms an association between the origin it is in with one or more web applications. It identifies apps uniquely by referencing manifest [=manifest/ids=].
Given [=origin=] |origin:origin|, a [=web-app-origin-association=]
file is expected to be downloadable from
[origin]/.well-known/web-app-origin-association.
Web Application Origin Migration allows a web application to indicate to the user agent that it moved from one origin to another (within the same site). This then enables the user agent to migrate an installed web application while preserving the user's installation and potentially their settings.
The following example shows how a web application hosted at
https://old.example.com can be migrated to
https://new.example.com. Both origins must be
[=same site=] and must explicitly agree to the migration.
First, the old application's manifest can optionally include a `migrate_to` member to signal to the user agent that it intends to move (alternatively the old application can redirect to the new application):
{
"name": "My App",
"id": "/",
"migrate_to": {
"id": "https://new.example.com/",
"install_url": "https://new.example.com/install"
}
}
Next, the new application's manifest includes a `migrate_from` member to claim the migration from the old application:
{
"name": "My New App",
"id": "/",
"migrate_from": [
{
"id": "https://old.example.com/",
"install_url": "https://old.example.com/install",
"behavior": "force"
}
]
}
Finally, the old origin must host a `web-app-origin-association` file to definitively validate that it permits the new application to take over. Without this file, a malicious new application could claim to migrate from an old application without permission.
{
"https://new.example.com/": {
"allow_migration": true
}
}
migrate_from member
The [=manifest/migrate_from=] member is a [=list=] of either [=strings=] or [=ordered maps=] that identifies the old web applications that are being migrated from.
If an entry is a [=string=], it is treated as the [=manifest/id=] of the old application.
If an entry is an [=ordered map=], it can have the following members:
id: A
[=string=] representing the [=manifest/id=] of the old application.
install_url: A [=string=]
representing a URL of a page that links to the old application's
manifest. A user agent can use this field to fetch the manifest of
the old application in order to apply updates even if every other
URL that is part of the old application redirects to the new
application.
behavior: A
[=string=] that can be either `"suggest"` or `"force"`. This is a
hint to the user agent that might influence how forceful the UI is
that the user agent presents to the user to tell them about the
migration.
migrate_to member
The [=manifest/migrate_to=] member is an optional [=ordered map=] that proactively signals a migration to a new application. It has the following members:
id: A
[=string=] representing the [=manifest/id=] of the new application.
install_url: A [=string=]
representing a URL of a page that links to the new application's
manifest. The manifest on this page needs to include a
[=manifest/migrate_from=] field that points back at this application
for the migration to be processed.
To validate origin migration, given [=URL=] |old_manifest_id:URL| and [=URL=] |new_manifest_id:URL|:
To process the `migrate_from` member, given [=ordered map=] |json:ordered map|, [=ordered map=] |manifest:ordered map|, and [=URL=] |manifest URL:URL|:
To process the `migrate_to` member, given [=ordered map=] |json:ordered map|, [=ordered map=] |manifest:ordered map|, and [=URL=] |manifest URL:URL|:
To prevent malicious actors from silently taking over applications (e.g., a simple calculator updating itself to mimic a banking app), the [=validate origin migration=] algorithm enforces a two-way handshake. Both the new and the old application origins must explicitly agree to the migration via the [=web-app-origin-association=] file.
Furthermore, migrations are restricted to be [=same site=] to ensure they are used for legitimate rebranding and architecture changes within an organization's control, rather than transferring ownership to unverified third parties.
User agents should consider including an explicit user confirmation dialog as part of the migration flow, especially if an update to security-sensitive fields (such as the app name and icons) is included.
Each external application resource represents an application related to the web application.
An [=external application resource=] can have the following members, some of which are required to be a [=valid external application resource=]:
A valid external application resource MUST have [=external application resource/platform=] member, and either an [=external application resource/url=] or an [=external application resource/id=] member (or both).
The platform member
represents the [=platform=] this [=external application resource=] is
associated with. A platform represents a
software distribution ecosystem or possibly an operating system. This
specification does not define the particular values for the
platform member.
An [=external application resource's=] url member is the
URL where the application can be found.
To process the `url` member of an application:
An [=external application resource's=] id member represents the
id which is used to represent the application on the platform.
An [=external application resource's=] min_version member
represents the minimum version of the application that is considered
related to this web app. This version is a string with
platform-specific syntax and semantics.
An [=external application resource's=] fingerprints member
represents an [=list=] of [=fingerprints=].
A fingerprint represents a set of cryptographic fingerprints used for verifying the application. A fingerprint has the following two members: type and value. Each of these are strings, but their syntax and semantics are platform-defined.
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:
The steps to notify that an install prompt is available are given by the following algorithm:
The steps to install the web application are given by the following algorithm:
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. These signals will vary per user agent, as each user agent will have its own heuristics to determine whether a web site is elegible of an install prompt. Implementers generally will provide documentation that describe their particular installabilty signals or other relevant criteria a web application needs to meet to be deemed installable.
Examples of possible installability signals for a web application that a user agent might implement:
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.
[=event|Events=] of this specification rely on the application life-cycle task source.
[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.
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:
prompt() method
The prompt method, when called, runs the following steps:
To request to present an install prompt with {{BeforeInstallPromptEvent}} event:
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.
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.