HTMLMediaElement: srcObject property - Web APIs

HTMLMediaElement: srcObject property
====================================

 The **`srcObject`** property of the
 `HTMLMediaElement` interface sets or returns the object which serves as
 the source of the media associated with the `HTMLMediaElement`.

 The object can be a `MediaStream`, a `MediaSource`, a
 `Blob`, or a `File` (which inherits from `Blob`).

**Note:** As of March 2020, only Safari has full support for `srcObject`, i.e. using `MediaSource`, `MediaStream`, `Blob`, and `File` objects as values. Other browsers support `MediaStream` objects; until they catch up, consider falling back to creating a URL with `URL.createObjectURL()` and assigning it to `HTMLMediaElement.src` (see below for an example). In addition, as of version 108 Chromium supports attaching a dedicated worker `MediaSource` object by assigning that object's `MediaSourceHandle` instance (transferred from the worker) to `srcObject`.

Value
-----

 A `MediaStream`, `MediaSource`, `Blob`, or
 `File` object (though see the compatibility table for what is actually
 supported).

Usage notes
-----------

 Older versions of the Media Source specification required using
 `URL.createObjectURL()` to create an object URL then
 setting `src` to that URL. Now you can just set
 `srcObject` to the `MediaStream` directly.

Examples
--------

### Basic example

 In this example, a `MediaStream` from a camera is assigned to a
 newly-created `<video>` element.

```js
const mediaStream = await navigator.mediaDevices.getUserMedia({ video: true });
const video = document.createElement("video");
video.srcObject = mediaStream;
```

 In this example, a new `MediaSource` is assigned to a newly-created
 `<video>` element.

```js
const mediaSource = new MediaSource();
const video = document.createElement("video");
video.srcObject = mediaSource;
```

### Supporting fallback to the src property

 The examples below support older browser versions that require you to create an object
 URL and assign it to `src` if `srcObject` isn't supported.

 First, a `MediaStream` from a camera is assigned to a newly-created
 `<video>` element, with fallback for older browsers.

```js
const mediaStream = await navigator.mediaDevices.getUserMedia({ video: true });
const video = document.createElement("video");
if ("srcObject" in video) {
  video.srcObject = mediaStream;
} else {
  // Avoid using this in new browsers, as it is going away.
  video.src = URL.createObjectURL(mediaStream);
}
```

 Second, a new `MediaSource` is assigned to a newly-created
 `<video>` element, with fallback for older browsers and browsers that
 don't yet support assignment of `MediaSource` directly.

```js
const mediaSource = new MediaSource();
const video = document.createElement("video");
// Older browsers may not have srcObject
if ("srcObject" in video) {
  try {
    video.srcObject = mediaSource;
  } catch (err) {
    if (err.name !== "TypeError") {
      throw err;
    }
    // Even if they do, they may only support MediaStream
    video.src = URL.createObjectURL(mediaSource);
  }
} else {
  video.src = URL.createObjectURL(mediaSource);
}
```

### Constructing a `MediaSource` in a worker and passing it to the main thread to play

The `MediaSource.handle` property can be accessed inside a dedicated worker and the resulting `MediaSourceHandle` object is then transferred over to the thread that created the worker (in this case the main thread) via a `postMessage()` call:

```js
// Inside dedicated worker
let mediaSource = new MediaSource();
let handle = mediaSource.handle;
// Transfer the handle to the context that created the worker
postMessage({ arg: handle }, [handle]);

mediaSource.addEventListener("sourceopen", () => {
  // Await sourceopen on MediaSource before creating SourceBuffers
  // and populating them with fetched media — MediaSource won't
  // accept creation of SourceBuffers until it is attached to the
  // HTMLMediaElement and its readyState is "open"
});
```

Over in the main thread, we receive the handle via a `message` event handler, attach it to a `<video>` via its `HTMLMediaElement.srcObject` property, and `play` the video:

```js
worker.addEventListener("message", (msg) => {
  let mediaSourceHandle = msg.data.arg;
  video.srcObject = mediaSourceHandle;
  video.play();
});
```

**Note:** `MediaSourceHandle`s cannot be successfully transferred into or via a shared worker or service worker.

Specifications
--------------

| Specification |
| --- |
| HTML Standard # dom-media-srcobject-dev |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


HTMLMediaElement: seeking event - Web APIs

HTMLMediaElement: seeking event
===============================

The `seeking` event is fired when a seek operation starts, meaning the Boolean `seeking` attribute has changed to `true` and the media is seeking a new position.

This event is not cancelable and does not bubble.

Syntax
------

Use the event name in methods like `addEventListener()`, or set an event handler property.

```js
addEventListener("seeking", (event) => {});

onseeking = (event) => {};
```

Event type
----------

A generic `Event`.

Examples
--------

These examples add an event listener for the HTMLMediaElement's `seeking` event, then post a message when that event handler has reacted to the event firing.

Using `addEventListener()`:

```js
const video = document.querySelector("video");

video.addEventListener("seeking", (event) => {
  console.log("Video is seeking a new position.");
});
```

Using the `onseeking` event handler property:

```js
const video = document.querySelector("video");

video.onseeking = (event) => {
  console.log("Video is seeking a new position.");
};
```

Specifications
--------------

| Specification |
| --- |
| HTML Standard # event-media-seeking |
| HTML Standard # handler-onseeking |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Related Events
--------------

* The HTMLMediaElement `playing` event
* The HTMLMediaElement `waiting` event
* The HTMLMediaElement `seeking` event
* The HTMLMediaElement `seeked` event
* The HTMLMediaElement `ended` event
* The HTMLMediaElement `loadedmetadata` event
* The HTMLMediaElement `loadeddata` event
* The HTMLMediaElement `canplay` event
* The HTMLMediaElement `canplaythrough` event
* The HTMLMediaElement `durationchange` event
* The HTMLMediaElement `timeupdate` event
* The HTMLMediaElement `play` event
* The HTMLMediaElement `pause` event
* The HTMLMediaElement `ratechange` event
* The HTMLMediaElement `volumechange` event
* The HTMLMediaElement `suspend` event
* The HTMLMediaElement `emptied` event
* The HTMLMediaElement `stalled` event
See also
--------

* `HTMLAudioElement`
* `HTMLVideoElement`
* `<audio>`
* `<video>`


HTMLMediaElement: seekToNextFrame() method - Web APIs

HTMLMediaElement: seekToNextFrame() method
==========================================

**Deprecated:** This feature is no longer recommended. Though some browsers might still support it, it may have already been removed from the relevant web standards, may be in the process of being dropped, or may only be kept for compatibility purposes. Avoid using it, and update existing code if possible; see the compatibility table at the bottom of this page to guide your decision. Be aware that this feature may cease to work at any time.

**Non-standard:** This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.

 The **`HTMLMediaElement.seekToNextFrame()`** method
 asynchronously advances the current play position to the next frame in the media.

**Warning:** This non-standard method is part of an experimentation process around support for
 non-real-time access to media for tasks including filtering, editing, and so forth.
 You should *not* use this method in production code, because its implementation
 may change—or be removed outright—without notice. You are, however, invited to
 experiment with it.

 This method lets you access frames of video media without the media being performed in
 real time. This also lets you access media using frames as a seek unit rather than
 timecodes (albeit only by seeking one frame at a time until you get to the frame you
 want). Possible uses for this method include filtering and editing of video content.

 This method returns immediately, returning a `Promise`, whose fulfillment
 handler is called when the seek operation is complete. In addition, a
 `seeked` event is sent to let interested parties know that a seek has taken
 place. If the seek fails because the media is already at the last frame, a
 `seeked` event occurs, followed immediately by an `ended` event.

 If there is no video on the media element, or the media isn't seekable, nothing
 happens.

Syntax
------

```js
seekToNextFrame()
```

### Parameters

None.

### Return value

A `Promise` which is fulfilled once the seek operation has completed.

Specifications
--------------

Not part of any specification.

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


HTMLMediaElement: play() method - Web APIs

HTMLMediaElement: play() method
===============================

 The `HTMLMediaElement`
**`play()`** method attempts to begin playback of the media.
 It returns a `Promise` which is resolved when playback has been
 successfully started.

 Failure to begin playback for any reason, such as
 permission issues, result in the promise being rejected.

Syntax
------

```js
play()
```

### Parameters

None.

### Return value

 A `Promise` which is resolved when playback has been started, or is
 rejected if for any reason playback cannot be started.

**Note:** Browsers released before 2019 may not return a value from
 `play()`.

### Exceptions

 The promise's **rejection handler** is called with a `DOMException` object
 passed in as its sole input parameter (as opposed to a traditional exception being
 thrown). Possible errors include:

`NotAllowedError` `DOMException`

 Provided if the user agent (browser) or operating system doesn't allow playback of media in the
 current context or situation. The browser may require the user to explicitly start
 media playback by clicking a "play" button, for example because of a Permissions Policy.

`NotSupportedError` `DOMException`

 Provided if the media source (which may be specified as a `MediaStream`,
 `MediaSource`, `Blob`, or `File`, for example)
 doesn't represent a supported media format.

 Other exceptions may be reported, depending on browser implementation details, media
 player implementation, and so forth.

Usage notes
-----------

 Although the term "autoplay" is usually thought of as referring to pages that
 immediately begin playing media upon being loaded, web browsers' autoplay policies also
 apply to any script-initiated playback of media, including calls to `play()`.

 If the user agent is configured not to allow automatic or
 script-initiated playback of media, calling `play()` will cause the returned
 promise to be immediately rejected with a `NotAllowedError`. Websites should
 be prepared to handle this situation. For example, a site should not present a user
 interface that assumes playback has begun automatically, but should instead update their
 UI based on whether the returned promise is fulfilled or rejected. See the
 example below for more information.

**Note:** The `play()` method may cause the user to be asked
 to grant permission to play the media, resulting in a possible delay before the
 returned promise is resolved. Be sure your code doesn't expect an immediate response.

 For even more in-depth information about autoplay and autoplay blocking, see our
 article Autoplay guide for media and Web Audio APIs.

Examples
--------

 This example demonstrates how to confirm that playback has begun and how to gracefully
 handle blocked automatic playback:

```js
let videoElem = document.getElementById("video");
let playButton = document.getElementById("playbutton");

playButton.addEventListener("click", handlePlayButton, false);
playVideo();

async function playVideo() {
  try {
    await videoElem.play();
    playButton.classList.add("playing");
  } catch (err) {
    playButton.classList.remove("playing");
  }
}

function handlePlayButton() {
  if (videoElem.paused) {
    playVideo();
  } else {
    videoElem.pause();
    playButton.classList.remove("playing");
  }
}
```

 In this example, playback of video is toggled off and on by the
 `async`
`playVideo()` function. It tries to play the video, and if successful sets
 the class name of the `playButton` element to `"playing"`. If
 playback fails to start, the `playButton` element's class is cleared,
 restoring its default appearance. This ensures that the play button matches the actual
 state of playback by watching for the resolution or rejection of the
 `Promise` returned by `play()`.

 When this example is executed, it begins by collecting references to the
 `<video>` element as well as the `<button>` used to toggle
 playback on and off. It then sets up an event handler for the `click` event
 on the play toggle button and attempts to automatically begin playback by calling
 `playVideo()`.

You can try out or remix this example in real time on Glitch.

Specifications
--------------

| Specification |
| --- |
| HTML Standard # dom-media-play-dev |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Web media technologies
* Learning: Video and audio content
* Autoplay guide for media and Web Audio APIs
* Using the Web Audio API


HTMLMediaElement: disableRemotePlayback property - Web APIs

HTMLMediaElement: disableRemotePlayback property
================================================

The **`disableRemotePlayback`** property of the `HTMLMediaElement` interface determines whether the media element is allowed to have a remote playback UI.

Value
-----

 A boolean value indicating whether the media element may have a remote playback
 UI. (false means "not disabled", which means "enabled")

Example
-------

```js
const obj = document.createElement("audio");
obj.disableRemotePlayback = true;
```

Specifications
--------------

| Specification |
| --- |
| Remote Playback API # the-disableremoteplayback-attribute |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


HTMLMediaElement: encrypted event - Web APIs

HTMLMediaElement: encrypted event
=================================

The `encrypted` event is fired when the media encounters some initialization data indicating it is encrypted.

This event is not cancelable and does not bubble.

Syntax
------

Use the event name in methods like `addEventListener()`, or set an event handler property.

```js
addEventListener("encrypted", (event) => {});

onencrypted = (event) => {};
```

Event type
----------

A `MediaEncryptedEvent`. Inherits from `Event`.

Event

MediaEncryptedEventEvent properties
----------------

`MediaEncryptedEvent.initDataType` Read only

Returns a case-sensitive string with the *type* of the format of the initialization data found.

`MediaEncryptedEvent.initData` Read only

Returns an `ArrayBuffer` containing the initialization data found. If there is no initialization data associated with the format, it returns `null`.

Specifications
--------------

| Specification |
| --- |
| Encrypted Media Extensions # dom-evt-encrypted |
| Encrypted Media Extensions # dom-htmlmediaelement-onencrypted |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `HTMLAudioElement`
* `HTMLVideoElement`
* `<audio>`
* `<video>`
* `MediaEncryptedEvent`


HTMLMediaElement: captureStream() method - Web APIs

HTMLMediaElement: captureStream() method
========================================

The **`captureStream()`** method of the `HTMLMediaElement` interface returns a `MediaStream` object which is streaming a real-time capture of the content being rendered in the media element.

This can be used, for example, as a source for a WebRTC `RTCPeerConnection`.

Syntax
------

```js
captureStream()
```

### Parameters

None.

### Return value

 A `MediaStream` object which can be used as a source for audio and/or
 video data by other media processing code, or as a source for WebRTC.

Examples
--------

 In this example, an event handler is established so that clicking a button starts
 capturing the contents of a media element with the ID `"playback"` into a
 `MediaStream`. The stream can then be used for other purposes—like a source
 for streaming over WebRTC, to allow sharing prerecorded videos with another person
 during a video call.

```js
document.querySelector(".playAndRecord").addEventListener("click", () => {
  const playbackElement = document.getElementById("playback");
  const captureStream = playbackElement.captureStream();
  playbackElement.play();
});
```

See Recording a media element for a longer and more intricate example and explanation.

Specifications
--------------

| Specification |
| --- |
| Media Capture from DOM Elements # dom-htmlmediaelement-capturestream |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

### Firefox-specific notes

 Prior to Firefox 51, you couldn't use `captureStream()` on a media element
 whose source is, itself, a `MediaStream` (like a `<video>`
 element which is presenting a stream being received over a
 `RTCPeerConnection`). Beginning in Firefox 51, this works. This means you
 can capture a stream from the video element and use `MediaRecorder` to
 record it. See Firefox bug 1259788 for details.

 However, `captureStream()` is still prefixed as
 `mozCaptureStream()` on Firefox for good reason: there are some quirks in the
 present implementation which are worth noting:

* The Firefox implementation currently only works as described in the specification
 when the media element's source is, itself, a `MediaStream`.
* If the media element's source isn't a `MediaStream`, the output from this
 method isn't compatible with the spec, and if you change the source after starting
 capture, the output capture stream can't accept the new source data due to that
 incompatibility, so no `MediaStreamTrack`s from the new source
 `MediaStream` are added to the captured stream, resulting in output that
 doesn't capture the updated source.
* Switching the source back to a `MediaStream` adds tracks back to the
 stream and it works again as expected.
* Calling `mozCaptureMediaStream()` on an element with a
 `MediaStream` source returns a stream that only contains tracks while the
 element is playing a `MediaStream`.
* If you call `mozCaptureMediaStream()` on a media element with no source
 media, its compatibility mode will be based on the first source that's added; for
 example, if it's a `MediaStream`, then the capture stream will only work
 with MediaStream sources from then on.
* This special behavior will be removed once the non-`MediaStream` source
 support is brought up to specification and the method is unprefixed. See
 Firefox bug 1259788 for details.
See also
--------

* Recording a media element
* MediaStream Recording API
* `HTMLCanvasElement.captureStream()`
* `MediaStream`
* WebRTC API


HTMLMediaElement: currentSrc property - Web APIs

HTMLMediaElement: currentSrc property
=====================================

 The **`HTMLMediaElement.currentSrc`** property contains the
 absolute URL of the chosen media resource. This could happen, for example, if the web
 server selects a media file based on the resolution of the user's display. The value
 is an empty string if the `networkState` property is `EMPTY`.

Value
-----

 A string object containing the absolute URL of the chosen media
 source; this may be an empty string if `networkState` is `EMPTY`;
 otherwise, it will be one of the resources listed by the
 `HTMLSourceElement` contained within the media element, or the value or src
 if no `<source>` element is provided.

Examples
--------

```js
const obj = document.createElement("video");
console.log(obj.currentSrc); // ""
```

Specifications
--------------

| Specification |
| --- |
| HTML Standard # dom-media-currentsrc-dev |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `HTMLMediaElement`: Interface used to define the `HTMLMediaElement.currentSrc` property


HTMLMediaElement: defaultPlaybackRate property - Web APIs

HTMLMediaElement: defaultPlaybackRate property
==============================================

The **`HTMLMediaElement.defaultPlaybackRate`** property indicates the default playback rate for the media.

Value
-----

A double. `1.0` is "normal speed," values lower than `1.0` make the media play slower than normal, higher values make it play faster.

### Exceptions

`NotSupportedError` `DOMException`

Thrown if the specified value is not supported.

Examples
--------

```js
const obj = document.createElement("video");
console.log(obj.defaultPlaybackRate); // 1
```

Specifications
--------------

| Specification |
| --- |
| HTML Standard # dom-media-defaultplaybackrate-dev |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `HTMLMediaElement`: Interface used to define the `HTMLMediaElement.defaultPlaybackRate` property


HTMLMediaElement: ended property - Web APIs

HTMLMediaElement: ended property
================================

 The **`HTMLMediaElement.ended`** property indicates whether the media
 element has ended playback.

Value
-----

 A boolean value which is `true` if the media contained in the
 element has finished playing.

 If the source of the media is a `MediaStream`, this value is
 `true` if the value of the stream's `active` property is `false`.

Examples
--------

```js
const obj = document.createElement("video");
console.log(obj.ended); // false
```

Specifications
--------------

| Specification |
| --- |
| HTML Standard # dom-media-ended-dev |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `HTMLMediaElement`: Interface used to define the `HTMLMediaElement.ended` property
* `MediaStream`
* `MediaStream.active`


HTMLMediaElement: playbackRate property - Web APIs

HTMLMediaElement: playbackRate property
=======================================

The **`HTMLMediaElement.playbackRate`** property sets the rate at which the media is being played back. This is used to implement user controls for fast forward, slow motion, and so forth. The normal playback rate is multiplied by this value to obtain the current rate, so a value of 1.0 indicates normal speed.

If `playbackRate` is negative, the media is played backwards.

The audio is muted when the fast forward or slow motion is outside a useful range (for example, Gecko mutes the sound outside the range `0.25` to `4.0`).

The pitch of the audio is corrected by default. You can disable pitch correction using the `HTMLMediaElement.preservesPitch` property.

Value
-----

A `double`. `1.0` is "normal speed," values lower than `1.0` make the media play slower than normal, higher values make it play faster. (**Default:** `1.0`)

Examples
--------

```js
const obj = document.createElement("video");
console.log(obj.playbackRate); // Expected Output: 1
```

Specifications
--------------

| Specification |
| --- |
| HTML Standard # dom-media-playbackrate-dev |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `HTMLMediaElement`: Interface used to define the `HTMLMediaElement.playbackRate` property


HTMLMediaElement: pause() method - Web APIs

HTMLMediaElement: pause() method
================================

 The **`HTMLMediaElement.pause()`** method will pause playback
 of the media, if the media is already in a paused state this method will have no effect.

Syntax
------

```js
pause()
```

### Parameters

None.

### Return value

None (`undefined`).

### Exceptions

None.

Specifications
--------------

| Specification |
| --- |
| HTML Standard # dom-media-pause-dev |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


HTMLMediaElement: emptied event - Web APIs

HTMLMediaElement: emptied event
===============================

The `emptied` event is fired when the media has become empty; for example, this event is sent if the media has already been loaded (or partially loaded), and the `load()` method is called to reload it.

This event is not cancelable and does not bubble.

Syntax
------

Use the event name in methods like `addEventListener()`, or set an event handler property.

```js
addEventListener("emptied", (event) => {});

onemptied = (event) => {};
```

Event type
----------

A generic `Event`.

Examples
--------

These examples add an event listener for the HTMLMediaElement's `emptied` event, then post a message when that event handler has reacted to the event firing.

Using `addEventListener()`:

```js
const video = document.querySelector("video");

video.addEventListener("emptied", (event) => {
  console.log("Uh oh. The media is empty. Did you call load()?");
});
```

Using the `onemptied` event handler property:

```js
const video = document.querySelector("video");

video.onemptied = (event) => {
  console.log("Uh oh. The media is empty. Did you call load()?");
};
```

Specifications
--------------

| Specification |
| --- |
| HTML Standard # event-media-emptied |
| HTML Standard # handler-onemptied |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Related Events
--------------

* The HTMLMediaElement `playing` event
* The HTMLMediaElement `waiting` event
* The HTMLMediaElement `seeking` event
* The HTMLMediaElement `seeked` event
* The HTMLMediaElement `ended` event
* The HTMLMediaElement `loadedmetadata` event
* The HTMLMediaElement `loadeddata` event
* The HTMLMediaElement `canplay` event
* The HTMLMediaElement `canplaythrough` event
* The HTMLMediaElement `durationchange` event
* The HTMLMediaElement `timeupdate` event
* The HTMLMediaElement `play` event
* The HTMLMediaElement `pause` event
* The HTMLMediaElement `ratechange` event
* The HTMLMediaElement `volumechange` event
* The HTMLMediaElement `suspend` event
* The HTMLMediaElement `emptied` event
* The HTMLMediaElement `stalled` event
See also
--------

* `HTMLAudioElement`
* `HTMLVideoElement`
* `<audio>`
* `<video>`


HTMLMediaElement: ended event - Web APIs

HTMLMediaElement: ended event
=============================

The `ended` event is fired when playback or streaming has stopped because the end of the media was reached or because no further data is available.

This event occurs based upon `HTMLMediaElement` (`<audio>` and `<video>`) fire `ended` when playback reaches the end of the media.

This event is not cancelable and does not bubble.

Syntax
------

Use the event name in methods like `addEventListener()`, or set an event handler property.

```js
addEventListener("ended", (event) => {});

onended = (event) => {};
```

Event type
----------

A generic `Event`.

Examples
--------

These examples add an event listener for the HTMLMediaElement's `ended` event, then post a message when that event handler has reacted to the event firing.

Using `addEventListener()`:

```js
const video = document.querySelector("video");

video.addEventListener("ended", (event) => {
  console.log(
    "Video stopped either because it has finished playing or no further data is available.",
  );
});
```

Using the `onended` event handler property:

```js
const video = document.querySelector("video");

video.onended = (event) => {
  console.log(
    "Video stopped either because it has finished playing or no further data is available.",
  );
};
```

Specifications
--------------

| Specification |
| --- |
| HTML Standard # event-media-ended |
| HTML Standard # handler-onended |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Related Events
--------------

* The HTMLMediaElement `playing` event
* The HTMLMediaElement `waiting` event
* The HTMLMediaElement `seeking` event
* The HTMLMediaElement `seeked` event
* The HTMLMediaElement `ended` event
* The HTMLMediaElement `loadedmetadata` event
* The HTMLMediaElement `loadeddata` event
* The HTMLMediaElement `canplay` event
* The HTMLMediaElement `canplaythrough` event
* The HTMLMediaElement `durationchange` event
* The HTMLMediaElement `timeupdate` event
* The HTMLMediaElement `play` event
* The HTMLMediaElement `pause` event
* The HTMLMediaElement `ratechange` event
* The HTMLMediaElement `volumechange` event
* The HTMLMediaElement `suspend` event
* The HTMLMediaElement `emptied` event
* The HTMLMediaElement `stalled` event
See also
--------

* `HTMLAudioElement`
* `HTMLVideoElement`
* `<audio>`
* `<video>`
* Media Capture and Streams
    + Media Capture and Streams: ended event
* Web Audio API
    + Web audio API: ended event


HTMLMediaElement: stalled event - Web APIs

HTMLMediaElement: stalled event
===============================

The `stalled` event is fired when the user agent is trying to fetch media data, but data is unexpectedly not forthcoming.

This event is not cancelable and does not bubble.

Syntax
------

Use the event name in methods like `addEventListener()`, or set an event handler property.

```js
addEventListener("stalled", (event) => {});

onstalled = (event) => {};
```

Event type
----------

A generic `Event`.

Examples
--------

These examples add an event listener for the HTMLMediaElement's `stalled` event, then post a message when that event handler has reacted to the event firing.

Using `addEventListener()`:

```js
const video = document.querySelector("video");

video.addEventListener("stalled", (event) => {
  console.log("Failed to fetch data, but trying.");
});
```

Using the `onstalled` event handler property:

```js
const video = document.querySelector("video");

video.onstalled = (event) => {
  console.log("Failed to fetch data, but trying.");
};
```

Specifications
--------------

| Specification |
| --- |
| HTML Standard # event-media-stalled |
| HTML Standard # handler-onstalled |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Related Events
--------------

* The HTMLMediaElement `playing` event
* The HTMLMediaElement `waiting` event
* The HTMLMediaElement `seeking` event
* The HTMLMediaElement `seeked` event
* The HTMLMediaElement `ended` event
* The HTMLMediaElement `loadedmetadata` event
* The HTMLMediaElement `loadeddata` event
* The HTMLMediaElement `canplay` event
* The HTMLMediaElement `canplaythrough` event
* The HTMLMediaElement `durationchange` event
* The HTMLMediaElement `timeupdate` event
* The HTMLMediaElement `play` event
* The HTMLMediaElement `pause` event
* The HTMLMediaElement `ratechange` event
* The HTMLMediaElement `volumechange` event
* The HTMLMediaElement `suspend` event
* The HTMLMediaElement `emptied` event
* The HTMLMediaElement `stalled` event
See also
--------

* `HTMLAudioElement`
* `HTMLVideoElement`
* `<audio>`
* `<video>`


HTMLMediaElement: volume property - Web APIs

HTMLMediaElement: volume property
=================================

 The **`HTMLMediaElement.volume`** property sets the volume at
 which the media will be played.

Value
-----

 A double values must fall between 0 and 1, where 0 is effectively muted and 1 is the
 loudest possible value.

Examples
--------

```js
const obj = document.createElement("audio");
console.log(obj.volume); // 1
obj.volume = 0.75;
```

Specifications
--------------

| Specification |
| --- |
| HTML Standard # dom-media-volume-dev |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `HTMLMediaElement`: Interface used to define the `HTMLMediaElement.volume` property
* `HTMLMediaElement.muted`


HTMLMediaElement: timeupdate event - Web APIs

HTMLMediaElement: timeupdate event
==================================

The `timeupdate` event is fired when the time indicated by the `currentTime` attribute has been updated.

The event frequency is dependent on the system load, but will be thrown between about 4Hz and 66Hz (assuming the event handlers don't take longer than 250ms to run). User agents are encouraged to vary the frequency of the event based on the system load and the average cost of processing the event each time, so that the UI updates are not any more frequent than the user agent can comfortably handle while decoding the video.

This event is not cancelable and does not bubble.

Syntax
------

Use the event name in methods like `addEventListener()`, or set an event handler property.

```js
addEventListener("timeupdate", (event) => {});

ontimeupdate = (event) => {};
```

Event type
----------

A generic `Event`.

Examples
--------

These examples add an event listener for the HTMLMediaElement's `timeupdate` event, then post a message when that event handler has reacted to the event firing. Remember, the event frequency is dependent on the system load.

Using `addEventListener()`:

```js
const video = document.querySelector("video");

video.addEventListener("timeupdate", (event) => {
  console.log("The currentTime attribute has been updated. Again.");
});
```

Using the `ontimeupdate` event handler property:

```js
const video = document.querySelector("video");

video.ontimeupdate = (event) => {
  console.log("The currentTime attribute has been updated. Again.");
};
```

Specifications
--------------

| Specification |
| --- |
| HTML Standard # event-media-timeupdate |
| HTML Standard # handler-ontimeupdate |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Related Events
--------------

* The HTMLMediaElement `playing` event
* The HTMLMediaElement `waiting` event
* The HTMLMediaElement `seeking` event
* The HTMLMediaElement `seeked` event
* The HTMLMediaElement `ended` event
* The HTMLMediaElement `loadedmetadata` event
* The HTMLMediaElement `loadeddata` event
* The HTMLMediaElement `canplay` event
* The HTMLMediaElement `canplaythrough` event
* The HTMLMediaElement `durationchange` event
* The HTMLMediaElement `timeupdate` event
* The HTMLMediaElement `play` event
* The HTMLMediaElement `pause` event
* The HTMLMediaElement `ratechange` event
* The HTMLMediaElement `volumechange` event
* The HTMLMediaElement `suspend` event
* The HTMLMediaElement `emptied` event
* The HTMLMediaElement `stalled` event
See also
--------

* `HTMLAudioElement`
* `HTMLVideoElement`
* `<audio>`
* `<video>`


HTMLMediaElement: videoTracks property - Web APIs

HTMLMediaElement: videoTracks property
======================================

 The read-only **`videoTracks`**
 property on `HTMLMediaElement` objects returns a
 `VideoTrackList` object listing all of the `VideoTrack`
 objects representing the media element's video tracks.

 The returned list is *live*; that is, as tracks are added to and removed from
 the media element, the list's contents change dynamically. Once you have a reference to
 the list, you can monitor it for changes to detect when new video tracks are added or
 existing ones removed. See VideoTrackList events
 to learn more about watching for changes to a media element's track list.

Value
-----

 A `VideoTrackList` object representing the list of video tracks included
 in the media element. The list of tracks can be accessed using array notation, or using
 the object's `getTrackById()` method.

 Each track is represented by a `VideoTrack` object which provides
 information about the track.

Specifications
--------------

| Specification |
| --- |
| HTML Standard # dom-media-videotracks-dev |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `HTMLMediaElement`: Interface used to define the `HTMLMediaElement.videoTracks` property
* `<video>`
* `VideoTrack`, `VideoTrackList`


HTMLMediaElement: setSinkId() method - Web APIs

HTMLMediaElement: setSinkId() method
====================================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

The **`HTMLMediaElement.setSinkId()`** method of the Audio Output Devices API sets the ID of the audio device to use for output and returns a `Promise`.

 This only works when the application is permitted to use the specified device.
 For more information see the security requirements below.

Syntax
------

```js
setSinkId(sinkId)
```

### Parameters

`sinkId`

The `MediaDeviceInfo.deviceId` of the audio output device.

### Return value

A `Promise` that resolves to `undefined`.

### Exceptions

`NotAllowedError` `DOMException`

Returned if a `speaker-selection` Permissions Policy is used to block use of audio outputs.

`NotFoundError` `DOMException`

Returned if the `deviceId` does not match any audio output device.

`AbortError` `DOMException`

Returned if switching the audio output device to the new audio device failed.

Security requirements
---------------------

Access to the API is subject to the following constraints:

* The method must be called in a secure context.
* Access may be gated by the `speaker-selection` HTTP Permission Policy.
* User permission is required to access a non-default device.
 The user grants permission by selecting the device associated with the ID in the prompt displayed by `MediaDevices.selectAudioOutput()`.
Examples
--------

 This example shows how to select an audio output device from the array returned by `MediaDevices.enumerateDevices()`, and set it as the sink for audio.
 Note that the result of `enumerateDevices()` only includes devices for which user permission is not required or has already been granted.

```js
const devices = await navigator.mediaDevices.enumerateDevices();
const audioDevice = devices.find((device) => device.kind === "audiooutput");
const audio = document.createElement("audio");
await audio.setSinkId(audioDevice.deviceId);
console.log(`Audio is being output on ${audio.sinkId}`);
```

Specifications
--------------

| Specification |
| --- |
| Audio Output Devices API # dom-htmlmediaelement-setsinkid |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `MediaDevices.selectAudioOutput()`
* `HTMLMediaElement.sinkId`


HTMLMediaElement: muted property - Web APIs

HTMLMediaElement: muted property
================================

 The **`HTMLMediaElement.muted`** property indicates whether the media
 element is muted.

Value
-----

 A boolean value. `true` means muted and `false` means
 not muted.

Examples
--------

```js
const obj = document.createElement("video");
console.log(obj.muted); // false
```

Specifications
--------------

| Specification |
| --- |
| HTML Standard # dom-media-muted-dev |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `HTMLMediaElement`: Interface used to define the `HTMLMediaElement.muted` property
* `HTMLMediaElement.defaultMuted`
* `HTMLMediaElement.volume`


MIDIOutput: clear() method - Web APIs

MIDIOutput: clear() method
==========================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

The **`clear()`** method of the `MIDIOutput` interface clears the queue of messages being sent to the output device.

Syntax
------

```js
clear()
```

### Parameters

None.

### Return value

None (`undefined`).

Specifications
--------------

| Specification |
| --- |
| Web MIDI API # dom-midioutput-clear |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


MIDIOutput: send() method - Web APIs

MIDIOutput: send() method
=========================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

The **`send()`** method of the `MIDIOutput` interface queues messages for the corresponding MIDI port. The message can be sent immediately, or with an optional timestamp to delay sending.

Syntax
------

```js
send(data)
send(data, timestamp)
```

### Parameters

`data`

A sequence of one or more valid MIDI messages. Each entry represents a single byte of data.

`timestamp` Optional

A `DOMHighResTimestamp` with the time in milliseconds when the message should be sent (relative to `Performance.timeOrigin`).

### Return value

None (`undefined`).

### Exceptions

`TypeError`

Thrown if `data` is not a valid sequence, or does not contain a valid MIDI message.

`InvalidAccessError` `DOMException`

Thrown if `data` is a system exclusive message, and the `MIDIAccess` did not enable exclusive access.

`InvalidStateError` `DOMException`

Thrown if the port is disconnected.

Examples
--------

In the following example a middle C note is sent immediately, followed by a note off message one second later.

```js
function sendMiddleC(midiAccess, portID) {
  const noteOnMessage = [0x90, 60, 0x7f]; // note on middle C, full velocity
  const output = midiAccess.outputs.get(portID);
  output.send(noteOnMessage); //omitting the timestamp means send immediately.
  output.send([0x80, 60, 0x40], window.performance.now() + 1000.0); // timestamp = now + 1000ms.
}
```

Specifications
--------------

| Specification |
| --- |
| Web MIDI API # dom-midioutput-send |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


Introduction to the File and Directory Entries API - Web APIs

Introduction to the File and Directory Entries API
==================================================

The File and Directory Entries API simulates a local file system that web apps can navigate around. You can develop apps that can read, write, and create files and directories in a sandboxed, virtual file system.

The File and Directory Entries API interacts with other related APIs. It was built on the File Writer API, which, in turn, was built on File API. Each of the APIs adds different functionality. These APIs are a giant evolutionary leap for web apps, which can now cache and process large amounts of data.

About this document
-------------------

This introduction discusses essential concepts and terminology in the File and Directory Entries API. It gives you the big picture and orients you to key concepts. It also describes restrictions that raise security errors if you ignore them. To learn more about terminology used in this API, see the Definitions section.

For the reference documentation on the File and Directory Entries API, see the reference landing page and its subpages.

The specification is still being defined and is subject to change.

Overview
--------

The File and Directory Entries API includes both asynchronous and synchronous versions of the interfaces. The asynchronous API can be used in cases where you don't want an outstanding operation to block the UI. The synchronous API, on the other hand, allows for simpler programming model, but it must be used with WebWorkers.

### Usefulness of the API

The File and Directory Entries API is an important API for the following reasons:

* It lets apps have offline and storage features that involve large binary blobs.
* It can improve performance by letting an app pre-fetch assets in the background and cache locally.
* It lets users of your web app directly edit a binary file that's in their local file directory.
* It provides a storage API that is already familiar to your users, who are used to working with file systems.

For examples of features you can create with this app, see the Sample use cases section.

### The File and Directory Entries API and other storage APIs

The File and Directory Entries API is an alternative to other storage APIs such as IndexedDB. The API is a better choice for apps that deal with blobs for the following reasons:

* The File and Directory Entries API offers client-side storage for use cases that are not addressed by databases. If you want to have large mutable chunks of data, the File and Directory Entries API is a much more efficient storage solution than a database.
* While Firefox supports blob storage for IndexedDB, Chrome currently does not (Chrome is still implementing support for blob storage in IndexedDB). If you are targeting Chrome for your app and you want to store blobs, the File and Directory Entries API and App Cache are your only choices. However, AppCache storage isn't locally mutable, and doesn't allow for fine-grained client-side management.
* In Chrome, you can use the File and Directory Entries API with the Quota Management API, which lets you ask for more storage and manage your storage quota.
### Sample use cases

The following are just a few examples of how you can use the File and Directory Entries API:

* Apps with persistent uploader
    + When a file or directory is selected for upload, you can copy the file into a local sandbox and upload a chunk at a time.
    + The app can restart uploads after an interruption, such as the browser being closed or crashing, connectivity getting interrupted, or the computer getting shut down.
* Video game or other apps with lots of media assets
    + The app downloads one or several large tarballs and expands them locally into a directory structure.
    + The app pre-fetches assets in the background, so the user can go to the next task or game level without waiting for a download.
* Audio or photo editor with offline access or local cache (great for performance and speed)
    + The app can write to files in place (for example, overwriting just the ID3/EXIF tags and not the entire file).
* Offline video viewer
    + The app can download large files (>1GB) for later viewing.
    + The app can access partially downloaded files (so that you can watch the first chapter of your DVD, even if the app is still downloading the rest of the content or if the app didn't complete the download because you had to run to catch a train).
* Offline web mail client
    + The client downloads attachments and stores them locally.
    + The client caches attachments for later upload.
Big concepts
------------

Before using the File and Directory Entries API, you must understand a few concepts.

### Virtualized file system

The API doesn't give you access to the local file system, nor is the sandbox really a section of the file system. Instead, it is a virtualized file system that looks like a full-fledged file system to the web app. It does not necessarily have a relationship to the local file system outside the browser.

What this means is that a web app and a desktop app cannot share the same file at the same time. The API does not let your web app reach outside the browser to files that desktop apps can also work on. You can, however, export a file from a web app to a desktop app. For example, you can use the File API, create a blob, redirect an iframe to the blob, and invoke the download manager.

### Different storage types

An application can request temporary or persistent storage. Temporary storage is easier to get, because the browser just gives it to you, but it is limited and can be deleted by the browser when it runs out of space. Persistent storage, on the other hand, might offer you larger space that can only be deleted by the user, but it requires the user to grant you permission.

Use temporary storage for caching and persistent storage for data that you want your app to keep—such as user-generated or unique data.

### Storage quotas

To prevent a web app from using up the entire disk, browsers might impose a quota for each app and allocate storage among web apps.

How storage space is granted or allocated and how you can manage storage are idiosyncratic to the browser, so you need to check the respective documentation of the browser. Google Chrome, for example, allows temporary storage beyond the 5 MB required in the specifications and supports the Quota Management API. To learn more about the Chrome-specific implementation, see Managing HTML Offline Storage.

### Asynchronous and synchronous versions

The File and Directory Entries API comes with asynchronous and synchronous versions. Both versions of the API offer the same capabilities and features. In fact, they are almost alike, except for a few differences.

WebWorkers

The asynchronous API can be used in either the document or WebWorkers context, while the synchronous API is for use with WebWorkers only.

Callbacks

The asynchronous API doesn't give you data by returning values; instead, you have to pass a callback function. You send requests for operations to happen, and get notified by callbacks. In contrast, the synchronous API does not use callbacks because the API methods return values.

Global methods of the asynchronous and synchronous APIs

The asynchronous API has the following global methods: `requestFileSystem()` and `resolveLocalFileSystemURL()`. These methods are members of both the window object and the worker global scope. The synchronous API, on the other hand, uses the following methods: `requestFileSystemSync()` and `resolveLocalFileSystemSyncURL()`. These synchronous methods are members of the worker's global scope only, not the window object.

The synchronous API can be simpler for some tasks. Its direct, in-order programming model can make code easier to read. The drawback of synchronous API has to do with its interactions with Web Workers, which has some limitations.

### Using the error callbacks for asynchronous API

When using the asynchronous API, always use the error callbacks. Although the error callbacks for the methods are optional parameters, they are not optional for your sanity. You want to know why your calls failed. At minimum, handle the errors to provide error messages, so you'll have an idea of what's going on.

### Interacting with other APIs

The File and Directory Entries API is designed to be used with other APIs and elements on the web platform. For example, you are likely to use one of the following:

* `fetch()`
* Drag and Drop API
* Web Workers (for the synchronous version of the File and Directory Entries API)
* The `input` element (to programmatically obtain a list of files from the element)
### Case-sensitive

The filesystem API is case-sensitive, and case-preserving.

Restrictions
------------

For security reasons, browsers impose restrictions on file access. If you ignore them, you will get security errors.

### Adhering to the same-origin policy

An origin is the domain, application layer protocol, and port of a URL of the document where the script is being executed. Each origin has its own associated set of file systems.

The security boundary imposed on file system prevents applications from accessing data with a different origin. This protects private data by preventing access and deletion. For example, while an app or a page in `http://www.example.com/app/` can access files from `http://www.example.com/dir/`, because they have the same origin, it cannot retrieve files from `http://www.example.com:8080/dir/` (different port) or `https://www.example.com/dir/` (different protocol).

### Unable to create and rename executable files

To prevent malicious apps from running hostile executables, you cannot create executable files within the sandbox of the File and Directory Entries API.

### Sandboxed file system

Because the file system is sandboxed, a web app cannot access another app's files. You also cannot read or write files to an arbitrary folder (for example, My Pictures and My Documents) on the user's hard drive.

### You cannot run your app from file://

You cannot run your app locally from `file://`. If you do so, the browser throws errors or your app fails silently. This restriction also applies to many of the file APIs, including Blob and FileReader.

For testing purposes, you can bypass the restriction on Chrome by starting the browser with the `--allow-file-access-from-files` flag. Use this flag only for this purpose.

Definitions
-----------

This section defines and explains terms used in the File and Directory Entries API.

blob

Stands for binary large object. A blob is a set of binary data that is stored as a single object. It is a general-purpose way to reference binary data in web applications. A blob can be an image or an audio file.

Blob

Blob—with a capital B—is a data structure that is immutable, which means that binary data referenced by a Blob cannot be modified directly. This makes Blobs act predictably when they are passed to asynchronous APIs.

persistent storage

Persistent storage is storage that stays in the browser unless the user expunges it or the app deletes it.

temporary storage

Transient storage is available to any web app. It is automatic and does not need to be requested, but the browser can delete the storage without warning.

Specifications
--------------

| Specification |
| --- |
| File and Directory Entries API # api-domfilesystem |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* File and Directory Entries API
* Read files in JavaScript (web.dev)


File and Directory Entries API support in Firefox - Web APIs

File and Directory Entries API support in Firefox
=================================================

The original File System API was created to let browsers implement support for accessing a sandboxed virtual file system on the user's storage device. Work to standardize the specification was abandoned back in 2012, but by that point, Google Chrome included its own implementation of the API. Over time, a number of popular sites and Web applications came to use it, often without providing any means of falling back to standard APIs or even checking to be sure the API is available before using it. Mozilla instead opted to implement other APIs which can be used to solve many of the same problems, such as IndexedDB; see the blog post Why no FileSystem API in Firefox? for more insights.

This has caused a number of popular websites not to work properly on browsers other than Chrome. Because of that, an attempt was made to create a spec offering the features of Google's API which consensus could be reached on. The result was the File and Directory Entries API. This subset of the API provided by Chrome is still not fully specified; however, for web compatibility reasons, it was decided to implement a subset of the API in Firefox; this was introduced in Firefox 50.

This article describes how the Firefox implementation of the File and Directory Entries API differs from other implementations and/or the specification.

Chrome deviations from the specification
----------------------------------------

The largest compatibility issue still remaining is that Chrome is still using older names for many of the interfaces in the API, since they implemented a related but different specification:

| Name in specification | Name in Google Chrome |
| --- | --- |
| `FileSystemDirectoryEntry` | `DirectoryEntry` |
| `FileSystemDirectoryEntrySync` | `DirectoryEntrySync` |
| `FileSystemDirectoryReader` | `DirectoryReader` |
| `FileSystemDirectoryReaderSync` | `DirectoryReaderSync` |
| `FileSystemEntry` | `Entry` |
| `FileSystemEntrySync` | `EntrySync` |
| `FileSystemFileEntry` | `FileEntry` |
| `FileSystemFileEntrySync` | `FileEntrySync` |

Be sure to account for this in your code by allowing for both names. Hopefully Chrome will be updated soon to use the newer names!

To ensure your code will work in both Chrome and other browsers, you can include code similar to the following:

```js
const FileSystemDirectoryEntry =
  window.FileSystemDirectoryEntry || window.DirectoryEntry;
const FileSystemEntry = window.FileSystemEntry || window.Entry;
```

Limitations in Firefox
----------------------

Next, let's look at limitations of the Firefox implementation of the API. In broad strokes, those limitations can be summarized as follows:

* Content scripts can't create file systems or initiate access to a file system. There are only two ways to get access to file system entries at this time:
    + The `<input>` element, using the `HTMLInputElement.webkitEntries` property to access an array of `FileSystemEntry` objects describing file system entries you can then read.
    + Using drag and drop by calling the `DataTransferItem.webkitGetAsEntry` method, which lets you get a `FileSystemFileEntry` or `FileSystemDirectoryEntry` for files dropped on a drop zone.
* Firefox doesn't support the `"filesystem:"` URL scheme.
See also
--------

* File and Directory Entries API
* Introduction to the File and Directory Entries API
* File and Directory Entries API specification
* Original specification for the File API: Directories and System (often called the "FileSystem API"); Google Chrome was the only browser to implement this **abandoned** API.


NotificationEvent: notification property - Web APIs

NotificationEvent: notification property
========================================

The **`notification`** read-only property of the `NotificationEvent` interface returns the instance of the `Notification` that was clicked to fire the event. The `Notification` provides read-only access to many properties that were set at the instantiation time of the Notification such as `tag` and `data` attributes that allow you to store information for deferred use in the `notificationclick` event.

Value
-----

A `Notification` object.

Examples
--------

```js
self.addEventListener("notificationclick", (event) => {
  console.log("On notification click");

  // Data can be attached to the notification so that you
  // can process it in the notificationclick handler.
  console.log(`Notification Tag: ${event.notification.tag}`);
  console.log(`Notification Data: ${event.notification.data}`);
  event.notification.close();

  // This looks to see if the current is already open and
  // focuses if it is
  event.waitUntil(
    clients
      .matchAll({
        type: "window",
      })
      .then((clientList) => {
        for (const client of clientList) {
          if (client.url === "/" && "focus" in client) return client.focus();
        }
        if (clients.openWindow) return clients.openWindow("/");
      }),
  );
});
```

Specifications
--------------

| Specification |
| --- |
| Notifications API Standard # ref-for-dom-notificationevent-notification |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


NotificationEvent: NotificationEvent() constructor - Web APIs

NotificationEvent: NotificationEvent() constructor
==================================================

The **`NotificationEvent()`** constructor creates a new `NotificationEvent` object.

Syntax
------

```js
new NotificationEvent(type, options)
```

### Parameters

`type`

 A string with the name of the event.
 It is case-sensitive and browsers set it to `notificationclick` or `notificationclose`.

`options`

An object that, *in addition of the properties defined in `ExtendableEvent()`*, can have the following properties:

`notification`

A `Notification` object to be used as the notification the event is dispatched on.

`action` Optional

An action associated with the notification. It defaults to `""`.

### Return value

A new `NotificationEvent()` object.

Examples
--------

```js
const n = new Notification("Hello");
const myNotificationEvent = new NotificationEvent(type, { notification: n });
```

Specifications
--------------

| Specification |
| --- |
| Notifications API Standard # dom-notificationevent-notificationevent |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


NotificationEvent: action property - Web APIs

NotificationEvent: action property
==================================

The **`action`** read-only property of the `NotificationEvent` interface returns the string ID of the notification button the user clicked. This value returns an empty string if the user clicked the notification somewhere other than an action button, or the notification does not have a button. The notification id is set during the creation of the Notification via the actions array attribute and can't be modified unless the notification is replaced.

Value
-----

A string.

Examples
--------

```js
self.registration.showNotification("New articles available", {
  actions: [{ action: "get", title: "Get now." }],
});

self.addEventListener(
  "notificationclick",
  (event) => {
    event.notification.close();
    if (event.action === "get") {
      synchronizeReader();
    } else {
      clients.openWindow("/reader");
    }
  },
  false,
);
```

Specifications
--------------

| Specification |
| --- |
| Notifications API Standard # dom-notification-actions |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


LayoutShift: hadRecentInput property - Web APIs

LayoutShift: hadRecentInput property
====================================

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`hadRecentInput`** read-only property of the `LayoutShift` interface returns `true` if `lastInputTime` is less than 500 milliseconds in the past.

Layout shifts are only a problem if the user is not expecting them, so layout shifts that are the result of user interactions (such as a user expanding a UI element) are often not considered in layout shift metrics. The `hadRecentInput` property allows you to exclude these shifts.

Value
-----

A boolean returning `true` if `lastInputTime` is less than 500 milliseconds in the past; `false` otherwise.

Examples
--------

### Ignoring recent user input for layout shift scores

The following example shows how the `hadRecentInput` property is used to only count layout shifts without recent user input.

```js
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // Count layout shifts without recent user input only
    if (!entry.hadRecentInput) {
      console.log("LayoutShift value:", entry.value);
      if (entry.sources) {
        for (const { node, currentRect, previousRect } of entry.sources)
          console.log("LayoutShift source:", node, {
            currentRect,
            previousRect,
          });
      }
    }
  }
});

observer.observe({ type: "layout-shift", buffered: true });
```

Specifications
--------------

| Specification |
| --- |
| Layout Instability # dom-layoutshift-hadrecentinput |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `LayoutShift.lastInputTime`


LayoutShift: sources property - Web APIs

LayoutShift: sources property
=============================

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`sources`** read-only property of the `LayoutShift` interface returns an array of `LayoutShiftAttribution` objects that indicate the DOM elements that moved during the layout shift.

Value
-----

An `Array` of `LayoutShiftAttribution` objects. This array will not contain more than five sources. If there are more than five elements impacted by the layout shift, the five most impactful elements are reported.

Examples
--------

### Logging layout shift sources

```js
const observer = new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    entry.sources.forEach((source) => {
      console.log(source);
    });
  });
});

observer.observe({ type: "layout-shift", buffered: true });
```

Specifications
--------------

| Specification |
| --- |
| Layout Instability # dom-layoutshift-sources |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `LayoutShiftAttribution`


LayoutShift: toJSON() method - Web APIs

LayoutShift: toJSON() method
============================

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`toJSON()`** method of the `LayoutShift` interface is a serializer; it returns a JSON representation of the `LayoutShift` object.

Syntax
------

```js
toJSON()
```

### Parameters

None.

### Return value

A `JSON` object that is the serialization of the `LayoutShift` object.

Examples
--------

### Using the toJSON method

In this example, calling `entry.toJSON()` returns a JSON representation of the `LayoutShift` object.

```js
const observer = new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    console.log(entry.toJSON());
  });
});

observer.observe({ type: "layout-shift", buffered: true });
```

This would log a JSON object like so:

```json
{
  "name": "",
  "entryType": "layout-shift",
  "startTime": 246.39999999850988,
  "duration": 0,
  "value": 0.0071167845054842215,
  "hadRecentInput": false,
  "lastInputTime": 0,
  "sources": [
    {
      "previousRect": {
        "x": 917,
        "y": 708,
        "width": 706,
        "height": 248,
        "top": 708,
        "right": 1623,
        "bottom": 956,
        "left": 917
      },
      "currentRect": {
        "x": 693,
        "y": 708,
        "width": 1154,
        "height": 472,
        "top": 708,
        "right": 1847,
        "bottom": 1180,
        "left": 693
      }
    }
  ]
}
```

To get a JSON string, you can use `JSON.stringify(entry)` directly; it will call `toJSON()` automatically.

Specifications
--------------

| Specification |
| --- |
| Layout Instability # dom-layoutshift-tojson |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `JSON`


LayoutShift: lastInputTime property - Web APIs

LayoutShift: lastInputTime property
===================================

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`lastInputTime`** read-only property of the `LayoutShift` interface returns the time of the most recent excluding input or `0` if no excluding input has occurred.

Layout shifts are only bad if the user wasn't expecting them. Many layout shift metrics (like Cumulative Layout Shift (CLS)) exclude shifts that occurred soon after certain user interactions. These interactions are called *excluding inputs*. Excluding inputs are:

* Any events which signal a user's active interaction with the document: (`mousedown`, `keydown`, and `pointerdown`)
* Any events which directly changes the size of the viewport.
* `change` events.

The `mousemove` and `pointermove` events are **not** excluding inputs.

Value
-----

A `DOMHighResTimeStamp` indicating the most recent excluding input time or `0` if no excluding input has occurred.

Examples
--------

### Logging last input times

Log excluding input times if excluding input has occurred.

```js
const observer = new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    if (entry.lastInputTime) {
      console.log(entry.lastInputTime);
    }
  });
});

observer.observe({ type: "layout-shift", buffered: true });
```

Specifications
--------------

| Specification |
| --- |
| Layout Instability # dom-layoutshift-lastinputtime |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `LayoutShift.hadRecentInput`


LayoutShift: value property - Web APIs

LayoutShift: value property
===========================

**Experimental:** **This is an experimental technology**
Check the Browser compatibility table carefully before using this in production.

The **`value`** read-only property of the `LayoutShift` interface returns the layout shift score calculated as the impact fraction (fraction of the viewport that was shifted) multiplied by the distance fraction (distance moved as a fraction of viewport).

Value
-----

A number between `0.0` and `1.0` indicating the layout shift score.

It is calculated as the impact fraction (fraction of the viewport that was shifted) multiplied by the distance fraction (distance moved as a fraction of viewport).
```

layout shift score = impact fraction * distance fraction
```

For more details, see Layout shift score on web.dev.

Examples
--------

### Logging the entry's layout shift score

The following example shows how use the `value` property to log the layout shift score.

```js
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // Count layout shifts without recent user input only
    if (!entry.hadRecentInput) {
      console.log("Entry's layout shift score:", entry.value);
    }
  }
});

observer.observe({ type: "layout-shift", buffered: true });
```

Specifications
--------------

| Specification |
| --- |
| Layout Instability # dom-layoutshift-value |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


SensorErrorEvent: SensorErrorEvent() constructor - Web APIs

SensorErrorEvent: SensorErrorEvent() constructor
================================================

 The **`SensorErrorEvent`** constructor
 creates a new `SensorErrorEvent` object which provides information about
 errors thrown by any of the interfaces based on `Sensor`.

Syntax
------

```js
new SensorErrorEvent(type, options)
```

### Parameters

`type`

 A string with the name of the event.
 It is case-sensitive and browsers always set it to `error`.

`options`

An object that, *in addition of the properties defined in `Event()`*, can have the following properties:

`error`

A `DOMException` object describing the error.

### Return value

A new `SensorErrorEvent` object.

Specifications
--------------

| Specification |
| --- |
| Generic Sensor API # dom-sensorerrorevent-sensorerrorevent |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


SensorErrorEvent: error property - Web APIs

SensorErrorEvent: error property
================================

 The **`error`** read-only property of
 the `SensorErrorEvent` interface returns the `DOMException`
 object passed in the event's constructor.

Value
-----

A `DOMException`.

Specifications
--------------

| Specification |
| --- |
| Generic Sensor API # dom-sensorerrorevent-error |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


WebGL tutorial - Web APIs

WebGL tutorial
==============

This tutorial describes how to use the `<canvas>` element to draw WebGL graphics, starting with the basics. The examples provided should give you some clear ideas of what you can do with WebGL and will provide code snippets that may get you started in building your own content.

WebGL enables web content to use an API based on OpenGL ES 2.0 to perform 3D rendering in an HTML `<canvas>` in browsers that support it without the use of plug-ins. WebGL programs consist of control code written in JavaScript and special effects code (shader code) that is executed on a computer's Graphics Processing Unit (GPU). WebGL elements can be mixed with other HTML elements and composited with other parts of the page or page background.

Before you start
----------------

Using the `<canvas>` element is not very difficult, but you do need a basic understanding of HTML and JavaScript. The `<canvas>` element and WebGL are not supported in some older browsers, but are supported in recent versions of all major browsers. In order to draw graphics on the canvas we use a JavaScript context object, which creates graphics on the fly.

In this tutorial
----------------

Getting started with WebGL

How to set up a WebGL context.

Adding 2D content to a WebGL context

How to render simple flat shapes using WebGL.

Using shaders to apply color in WebGL

Demonstrates how to add color to shapes using shaders.

Animating objects with WebGL

Shows how to rotate and translate objects to create simple animations.

Creating 3D objects using WebGL

Shows how to create and animate a 3D object (in this case, a cube).

Using textures in WebGL

Demonstrates how to map textures onto the faces of an object.

Lighting in WebGL

How to simulate lighting effects in your WebGL context.

Animating textures in WebGL

Shows how to animate textures; in this case, by mapping an Ogg video onto the faces of a rotating cube.


Data in WebGL - Web APIs

Data in WebGL
=============

Shader programs have access to three kinds of data storage, each of which has a specific use case. Each kind of variable is accessible by one or both types of shader program (depending on the data store type) and possibly by the site's JavaScript code, depending on the specific type of variable.

GLSL data types
---------------

See Data Types in the GLSL documentation.

GLSL variables
--------------

There are three kinds of "variable" or data storage available in GLSL, each of which with its own purpose and use cases: **attributes**, **varyings**, and **uniforms**.

### Attributes

**Attributes** are GLSL variables which are only available to the vertex shader (as variables) and the JavaScript code. Attributes are typically used to store color information, texture coordinates, and any other data calculated or retrieved that needs to be shared between the JavaScript code and the vertex shader.

```js
// init colors
const vertexColors = [
  vec4(0.0, 0.0, 0.0, 1.0), // black
  vec4(1.0, 0.0, 0.0, 1.0), // red
  vec4(1.0, 1.0, 0.0, 1.0), // yellow
  vec4(0.0, 1.0, 0.0, 1.0), // green
  vec4(0.0, 0.0, 0.0, 1.0), // black
  vec4(1.0, 0.0, 0.0, 1.0), // red
  vec4(1.0, 1.0, 0.0, 1.0), // yellow
  vec4(0.0, 1.0, 0.0, 1.0), // green
];
const cBuffer = gl.createBuffer();
```

```js
// continued
// create buffer to store colors and reference it to "vColor" which is in GLSL
gl.bindBuffer(gl.ARRAY\_BUFFER, cBuffer);
gl.bufferData(gl.ARRAY\_BUFFER, flatten(vertexColors), gl.STATIC\_DRAW);

const vColor = gl.getAttribLocation(program, "vColor");
gl.vertexAttribPointer(vColor, 4, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vColor);
```

```cpp
//glsl
attribute  vec4 vColor;

void main()
{
  fColor = vColor;
}
```

### Varyings

**Varyings** are variables that are declared by the vertex shader and used to pass data from the vertex shader to the fragment shader. This is commonly used to share a vertex's normal vector after it has been computed by the vertex shader.

<<how to use>>

### Uniforms

**Uniforms** are set by the JavaScript code and are available to both the vertex and fragment shaders. They're used to provide values that will be the same for everything drawn in the frame, such as lighting positions and magnitudes, global transformation and perspective details, and so forth.

<<add details>>

Buffers
-------

<<add information>>

Textures
--------

<<add information>>


Compressed texture formats - Web APIs

Compressed texture formats
==========================

The WebGL API provides methods to use compressed texture formats. These are useful to increase texture detail while limiting the additional video memory necessary. By default, no compressed formats are available: a corresponding compressed texture format extension must first be enabled.

Usage
-----

Unless otherwise specified, this article applies to both WebGL 1 and 2 contexts.

If supported, textures can be stored in a compressed format in video memory. This allows for additional detail while limiting the added video memory necessary. Textures are uncompressed on the fly when being accessed by a shader. Note that this advantage doesn't translate to network bandwidth: while the formats are better than uncompressed data, they are in general far worse than standard image formats such as PNG and JPG.

As compressed textures require hardware support, therefore no specific formats are required by WebGL; instead, a context can make different formats available, depending on hardware support. This site shows which formats are supported in the used browser.

Usage of compressed formats first requires activating the respective extension with `WebGLRenderingContext.getExtension()`. If supported, it will return an extension object with constants for the added formats and the formats will also be returned by calls to `gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS)`. (E.g. `ext.COMPRESSED_RGBA_S3TC_DXT1_EXT` for the `WEBGL_compressed_texture_s3tc` extension.) These can then be used with `compressedTexImage[23]D` or `compressedTexSubImage[23]D` instead of `texImage2D` calls.

Note that WebGL makes no functionality available to compress or decompress textures: they must already be in a compressed format and can then be directly uploaded to video memory.

All formats support 2D textures. Which formats support `TEXTURE_2D_ARRAY` and `TEXTURE_3D` targets (in combination with `compressedTexImage3D`) are noted in the following table.

| Extension | Notes | TEXTURE\_2D\_ARRAY | TEXTURE\_3D |
| --- | --- | --- | --- |
| WEBGL\_compressed\_texture\_astc |  | Yes | Yes |
| WEBGL\_compressed\_texture\_etc |  | Yes | No |
| WEBGL\_compressed\_texture\_etc1\* | Not usable with compressedTexSubImage2D/copyTexSubImage2D. | No | No |
| WEBGL\_compressed\_texture\_pvrtc | Width and height must be powers of 2. | No | No |
| WEBGL\_compressed\_texture\_s3tc | Width and height must be multiples of 4. | Yes | No |
| WEBGL\_compressed\_texture\_s3tc\_srgb | Width and height must be multiples of 4. | ? | No |

Examples
--------

```js
async function getCompressedTextureIfAvailable(gl) {
  const texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE\_2D, texture); // create texture object on GPU
  const ext = gl.getExtension("WEBGL\_compressed\_texture\_s3tc"); // will be null if not supported
  if (ext) {
    // the file is already in the correct compressed format
    const dataArrayBuffer = await fetch(
      "/textures/foobar512x512.RGBA\_S3TC\_DXT1",
    ).then((response) => response.arrayBuffer());
    gl.compressedTexImage2D(
      gl.TEXTURE\_2D,
      0, // set the base image level
      ext.COMPRESSED\_RGBA\_S3TC\_DXT1\_EXT, // the compressed format we are using
      512,
      512, // width, height of the image
      0, // border, always 0
      new DataView(dataArrayBuffer),
    );
    gl.generateMipMap(); // create mipmap levels, like we would for a standard image
    return texture;
  }
}
```


Using WebGL extensions - Web APIs

Using WebGL extensions
======================

WebGL, like its sister APIs (OpenGL and OpenGL ES), supports extensions. A complete list of extensions is available in the khronos webgl extension registry.

**Note:** In WebGL, unlike in other GL APIs, extensions are only available if explicitly requested.

Canonical extension names, vendor prefixes and preferences
----------------------------------------------------------

Extensions may be supported by browser vendors before being officially ratified (but only when they are in draft stage). In that case, their name can be prefixed by the vendor prefix (`MOZ_`, `WEBKIT_`, etc.) or the extension is only available once a browser preference has been toggled.

If you wish to work with the bleeding edge of extensions, and want to keep working on upon ratification (assuming, of course, that the extension doesn't change in incompatible ways), that you query the canonical extension name as well as the vendor extension name. For instance:

```js
const ext =
  gl.getExtension("OES\_vertex\_array\_object") ||
  gl.getExtension("MOZ\_OES\_vertex\_array\_object") ||
  gl.getExtension("WEBKIT\_OES\_vertex\_array\_object");
```

Note that, vendor prefix have been discouraged thus most browser implement experimental extensions behind a feature flag rather than vendor prefix.

The feature flags are:

* `webgl.enable-draft-extensions` in Firefox
* `chrome://flags/#enable-webgl-draft-extensions` in Chromium based browsers (Chrome, Opera).
Naming conventions
------------------

WebGL extensions are prefixed with "ANGLE", "OES", "EXT" or "WEBGL". These prefixes reflect origin and intent:

* `ANGLE_`: Extensions that are written by the ANGLE library authors.
* `OES_` and `KHR_`: Extensions that mirror functionality from OpenGL ES (OES) or OpenGL API extensions approved by the respective architecture review boards (Khronos).
* `OVR_`: Extensions that optimize for virtual reality.
* `EXT_`: Extensions that mirror other OpenGL ES or OpenGL API extensions.
* `WEBGL_`: Extensions that are WebGL-specific and intended to be compatible with multiple web browsers. It should also be used for extensions which originated with the OpenGL ES or OpenGL APIs, but whose behavior has been significantly altered.
Querying available extensions
-----------------------------

The WebGL context supports querying what extensions are available.

```js
const available_extensions = gl.getSupportedExtensions();
```

The `WebGLRenderingContext.getSupportedExtensions()` method returns an array of strings, one for each supported extension.

Extension list
--------------

The current extensions are:

* `ANGLE_instanced_arrays`
* `EXT_blend_minmax`
* `EXT_color_buffer_float`
* `EXT_color_buffer_half_float`
* `EXT_disjoint_timer_query`
* `EXT_float_blend`
Experimental
* `EXT_frag_depth`
* `EXT_shader_texture_lod`
* `EXT_sRGB`
* `EXT_texture_compression_bptc`
* `EXT_texture_compression_rgtc`
* `EXT_texture_filter_anisotropic`
* `EXT_texture_norm16`
* `KHR_parallel_shader_compile`
* `OES_draw_buffers_indexed`
* `OES_element_index_uint`
* `OES_fbo_render_mipmap`
* `OES_standard_derivatives`
* `OES_texture_float`
* `OES_texture_float_linear`
* `OES_texture_half_float`
* `OES_texture_half_float_linear`
* `OES_vertex_array_object`
* `OVR_multiview2`
* `WEBGL_color_buffer_float`
* `WEBGL_compressed_texture_astc`
* `WEBGL_compressed_texture_etc`
* `WEBGL_compressed_texture_etc1`
* `WEBGL_compressed_texture_pvrtc`
* `WEBGL_compressed_texture_s3tc`
* `WEBGL_compressed_texture_s3tc_srgb`
* `WEBGL_debug_renderer_info`
* `WEBGL_debug_shaders`
* `WEBGL_depth_texture`
* `WEBGL_draw_buffers`
* `WEBGL_lose_context`
* `WEBGL_multi_draw`
Enabling an extension
---------------------

Before an extension can be used it has to be enabled using `WebGLRenderingContext.getExtension()`. For example:

```js
const float_texture_ext = gl.getExtension("OES\_texture\_float");
```

The return value is `null` if the extension is not supported, or an extension object otherwise.

Extension objects
-----------------

If an extension defines specific symbols or functions that are not available in the core specification of WebGL, they will be available on the extension object returned by the call to `gl.getExtension()`.

See also
--------

* `WebGLRenderingContext.getSupportedExtensions()`
* `WebGLRenderingContext.getExtension()`
* webglreport.com
* web3dsurvey.com - WebGL Extension Support Survey