This specification defines an API allowing web pages and [=installed web applications=] to set a badge on the document, or an application-wide badge, shown in an operating-system-specific place associated with the application (such as the shelf or home screen), for the purpose of notifying the user when the state of the page or application has changed (e.g., when new messages have arrived), without showing a more heavyweight notification.

This is an early draft of the Badging API spec.

Usage examples

The following example shows how an email application might set a badge showing the unread count associated with the current document, which is updated whenever the client polls for mail from the server.

        function pollForMail() {
          // ... Fetch unread mail from server. ...

          // Set the document badge. If getUnreadCount() returns 0, this is
          // equivalent to navigator.clearClientBadge().
          navigator.setClientBadge(getUnreadCount());
        }
      

The next example shows how a game might show when it is the player's turn. Again, this associates the badge with the current document.

        function showPlayerTurn(playerTurnId) {
          if (playerTurnId === localPlayerId)
            navigator.setClientBadge();
          else
            navigator.clearClientBadge();
        }
      

A separate set of methods set the badge on the [=installed web application=], if any, whose [=manifest/navigation scope=] this document is within. The badge might show up on the application's icon in the operating system shelf. These examples work the same as above, except that the badge has global scope (if multiple documents within the same application set or clear a badge, the most recent one takes effect), and can continue being seen even after the last document closes.

        function pollForMail() {
          // ... Fetch unread mail from server. ...

          // Set the app badge.
          navigator.setAppBadge(getUnreadCount());
        }
      
        function showPlayerTurn(playerTurnId) {
          if (playerTurnId === localPlayerId)
            navigator.setAppBadge();
          else
            navigator.clearAppBadge();
        }
      

To show a badge on both the document(s) and app icon(s), use both APIs together.

Badge model

A badge may be one of the following values:

Each [=document=] and each [=installed web application=] is associated with a badge value, which is initialized to nothing.

The user agent MAY reset an application's badge to nothing at its discretion (for example, when the system is restarted).

If a badge is nothing, it is said to be "cleared". Otherwise, it is said to be "set".

Badge display

When a document's badge is set, if the document's [=browsing context=] is a [=top-level browsing context=], the user agent SHOULD display the document's badge value alongside the other identifying information for that document (for example, on top of the document's icon or near its title).

The user agent is not expected to display a badge associated with a document that is not a [=top-level browsing context=], although it is allowed to. A user agent does not need to store the badge for a non-top-level browsing context if it does not intend to display it.

When the application's badge is set, the user agent SHOULD display the application's badge alongside any symbolic representations of the application in the user's operating system (for example, as a small overlay on top of the application's icon).

If the badge is set to special value flag, the user agent SHOULD show an indicator with a non-specific symbol (such as a coloured circle).

The user agent MAY simplify or degrade the data in any way. For example, a large integer may be saturated (for example, as "99+"). The font and formatting are entirely at the user agent's discretion. The user agent MAY ignore the data, and merely show a marker when the status is set.

When presenting a badge, it SHOULD be formatted according to the user's locale settings. For example, the badge content '7' should be displayed as '7' in the locale 'en-NZ' but as '٧' in 'ar-EG'.

Extensions to the `Navigator` and `WorkerNavigator` interfaces

The {{Navigator}} and {{WorkerNavigator}} interfaces are extended with methods for setting and clearing both the document and application badge indicators from documents and service workers, respectively.

        // Methods only exposed on documents.
        [SecureContext]
        partial interface Navigator {
          Promise<undefined> setClientBadge(optional [EnforceRange] unsigned long long contents);
          Promise<undefined> clearClientBadge();
        };

        // Methods exposed on both documents and service workers.
        [SecureContext]
        interface mixin NavigatorBadge {
          Promise<undefined> setAppBadge(optional [EnforceRange] unsigned long long contents);
          Promise<undefined> clearAppBadge();
        };

        Navigator includes NavigatorBadge;
        WorkerNavigator includes NavigatorBadge;
      

User agents that never display document badges SHOULD NOT expose the {{Navigator/setClientBadge()}} and {{Navigator/clearClientBadge()}} methods. Similarly, user agents that never display application badges SHOULD NOT expose the {{NavigatorBadge/setAppBadge()}} and {{NavigatorBadge/clearAppBadge()}} methods.

This is important as a feature-detection mechanism to allow sites to determine whether setting a badge will have any effect, based on the presence of the methods. In particular, sites can use the absence of {{Navigator/setClientBadge()}} as a condition for displaying a fallback badge in the page's [^title^] or [=link type "icon"=].

setClientBadge() method

When the {{Navigator/setClientBadge()}} method is called on |navigator:Navigator| with argument |contents:unsigned long long|:

  1. Return [=a promise resolved with=] undefined, and [=in parallel=]:
    1. Let |document:Document| be |navigator|'s [=relevant settings object=]'s [=environment settings object/responsible document=].
    2. If |contents| is omitted, set the badge associated with |document| to flag.
    3. Else, if |contents| is 0, set the badge associated with |document| to nothing.
    4. Else, set the badge associated with |document| to |contents|.

clearClientBadge() method

When the {{Navigator/clearClientBadge()}} method is called on |navigator:Navigator|, return [=a promise resolved with=] undefined, and [=in parallel=], set the the badge associated with |navigator|'s [=relevant settings object=]'s [=environment settings object/responsible document=] to nothing.

setAppBadge() method

When the {{NavigatorBadge/setAppBadge()}} method is called on |navigator:Navigator| with argument |contents:unsigned long long|:

  1. If |navigator|'s [=relevant settings object=] does not have a [=environment settings object/responsible document=], and is not a [=service worker client=], return [=a promise rejected with=] a {{"NotSupportedError"}} {{DOMException}}.
  2. Otherwise, return [=a promise resolved with=] undefined, and [=in parallel=]:
    1. Let |result:set of applications| be the result of determining the matching applications on |navigator|'s [=relevant settings object=].
    2. For each |app:application| in |result|:
      1. If |contents| is omitted, set the badge associated with |app| to flag.
      2. Else, if |contents| is 0, set the badge associated with |app| to nothing.
      3. Else, set the badge associated with |app| to |contents|.

clearAppBadge() method

When the {{NavigatorBadge/clearAppBadge()}} method is called on |navigator:Navigator|:

  1. If |navigator|'s [=relevant settings object=] does not have a [=environment settings object/responsible document=], and is not a [=service worker client=], return [=a promise rejected with=] a {{"NotSupportedError"}} {{DOMException}}.
  2. Otherwise, return [=a promise resolved with=] undefined, and [=in parallel=]:
    1. Let |result:set of applications| be the result of determining the matching applications on |navigator|'s [=relevant settings object=].
    2. Set the badge associated with each application in |result| to nothing.

Determining the set of matching applications

This algorithm is used to decide which app(s) receive a badge when the {{NavigatorBadge/setAppBadge()}} method is called from either a document or service worker context.

If called from a document context, the badge is applied to at most one application: the one with the most specific scope whose scope encloses this document URL.

If called from a service worker context, the badge is applied to all applications whose scope sits within the service worker's scope.

The steps for determining the matching applications takes an [=environment settings object=] |environment:environment settings object| that either has a [=environment settings object/responsible document=], or is a [=service worker client=], and returns a [=set=] of [=installed web applications=]:

  1. If |environment| has a [=environment settings object/responsible document=] |document:Document|:
    1. Let |apps:set of applications| be the [=set=] of [=installed web applications=] such that |document|'s {{Document/URL}} is within scope of the application's manifest. (Order is not important.)
    2. [=list/Remove=] all elements of |apps| other than the one with the longest (i.e., most specific) [=manifest/navigation scope=].
    3. Return |apps|.
  2. Otherwise (|environment| is a [=service worker client=]):
    1. Return the [=set=] of [=installed web applications=] whose [=manifest/navigation scope=] is within scope (as defined in [[AppManifest]]) of |environment|'s [=service worker/containing service worker registration=]'s [=service worker registration/scope url=]. (Order is not important.)

Security and privacy considerations

The API is write-only by design. There is no way for a site to read back the value of a badge that was previously set, to ensure that the application badge cannot be used as a storage or fingerprinting mechanism.

Accessibility considerations