Starting up and shutting down a WebXR session - Web APIs

Starting up and shutting down a WebXR session
=============================================

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

Assuming you're already familiar with 3D graphics in general and WebGL in particular, taking that next bold step into mixed reality—the idea of presenting artificial scenery or objects in addition to or in place of the real world—is not overly complicated. Before you can begin to render your augmented or virtual reality scenario, you need to create and set up the WebXR session, and you should know how to shut it down properly as well. You will learn how to do these things in this article.

Accessing the WebXR API
-----------------------

Your app's access to the WebXR API begins with the `XRSystem` object. This object represents the overall WebXR device suite available to you through the hardware and drivers available on the user's equipment. There is a global `XRSystem` object available for use by your document through the `Navigator` property `xr`, which returns the `XRSystem` object if suitable XR hardware is available for your use given the hardware available and your document's environment.

Thus the simplest code that fetches the `XRSystem` object is:

```js
const xr = navigator.xr;
```

The value of `xr` will be `null` or `undefined` if WebXR isn't available.

### WebXR availability

As a new and still in development API, WebXR support is limited to specific devices and browsers; and even on those, it may not be enabled by default. There may be options available to allow you to experiment with WebXR even if you don't have a compatible system, however.

#### WebXR polyfill

The team designing the WebXR specification has published a WebXR polyfill which you can use to simulate WebXR on browsers which don't have support for the WebXR APIs. If the browser supports the older WebVR API, that is used. Otherwise, the polyfill falls back to an implementation which uses Google's Cardboard VR API.

The polyfill is maintained alongside the specification, and is kept up to date with the specification. Additionally, it is updated to maintain compatibility with browsers as their support for WebXR and other technologies related to it and to the implementation of the polyfill change over time.

Be sure to read the readme carefully; the polyfill comes in several versions depending on what degree of compatibility with newer JavaScript features your target browsers include.

#### WebXR API Emulator extension

Mozilla WebXR team has created a WebXR API Emulator browser extension, compatible with both Firefox and Chrome, which emulates the WebXR API, simulating a variety of compatible devices such as the HTC Vive, the Oculus Go and Oculus Quest, Samsung Gear, and Google Cardboard. With the extension in place, you can open up a developer tools panel that lets you control the position and orientation of the headset and any hand controllers, as well as button presses on the controllers.

##### Emulator usage

While somewhat awkward compared to using an actual headset, this makes it possible to experiment with and developer WebXR code on a desktop computer, where WebXR isn't normally available. It also lets you perform some basic testing before taking your code to a real device. Be aware, however, that the emulator does not yet completely emulate all of the WebXR API, so you may run into problems you're not expecting. Again, carefully read the readme file and make sure you're aware of the limitations before you begin.

**Important:** You should *always* test your code on actual AR and/or VR hardware before releasing or shipping a product! Emulated, simulated, or polyfilled environments are *not* an adequate substitute for actual testing on physical devices.

##### Getting the extension

Download the WebXR API Emulator for your supported browser below:

* Google Chrome
* Mozilla Firefox

The source code for the extension is also available on GitHub.

##### Emulator issues and notes

While this isn't the place for a full article about the extension, there are some specific things worth mentioning.

Version 0.4.0 of the extension was announced on March 26, 2020. It introduced support for augmented reality (AR) through the WebXR AR Module, which has is approaching a stable state. Documentation for AR is forthcoming shortly here on MDN.

Other improvements include updating the emulator to rename the `XR` interface to `XRSystem`, introduce support for squeeze (grip) input sources, and add support for the `XRInputSource` property `profiles`.

### Context requirements

A WebXR compatible environment starts with a securely-loaded document. Your document needs to either have been loaded from the local drive (such as by using a URL such as `http://localhost/…`), or using HTTPS when loading the page. The JavaScript code must, likewise, have been loaded securely.

If the document wasn't loaded securely, you won't get very far. The `navigator.xr` property doesn't even exist if the document wasn't loaded securely. This may also be the case if there is no compatible XR hardware available. Either way, you need to be prepared for the lack of an `xr` property and either gracefully handle the error or provide some form of fallback.

### Falling back to the WebXR polyfill

One fallback option is the WebXR polyfill, provided by the Immersive Web Working Group that's in charge of the WebXR standardization process. The polyfill brings support for WebXR to browsers that don't have native WebXR support, and smooths out the inconsistencies among implementations in the browsers that do have it, so it can sometimes also be useful even if WebXR is natively available.

Here we define a `getXR()` function, which returns the `XRSystem` object after optionally installing the polyfill, assuming that the polyfill has been included or loaded using a prior `<script>` tag.

```js
let webxrPolyfill = null;

function getXR(usePolyfill) {
  let tempXR;

  switch (usePolyfill) {
    case "if-needed":
      tempXR = navigator.xr;
      if (!tempXR) {
        webxrPolyfill = new WebXRPolyfill();
        tempXR = webxrPolyfill;
      }
      break;
    case "yes":
      webxrPolyfill = new WebXRPolyfill();
      tempXR = webxrPolyfill;
      break;
    case "no":
    default:
      tempXR = navigator.xr;
      break;
  }

  return tempXR;
}

const nativeXr = getXR("no"); // Get the native XRSystem object
const polyfilledXr = getXR("yes"); // Always returns an XRSystem from the polyfill
const xr = getXR("if-needed"); // Use the polyfill only if navigator.xr missing
```

The returned `XRSystem` object can then be used according to the documentation provided here on MDN. The global variable `webxrPolyfill` is used only to retain a reference to the polyfill in order to ensure that it remains available until you no longer need it. Setting it to `null` signals that the polyfill can be garbage collected when no objects depending on it are using it anymore.

Of course, you can simplify this depending on your needs; since your app is probably not going to go back and forth much on whether or not to use the polyfill, you can simplify this to just the specific case you need.

### Permissions and security

There are a number of security measures in place revolving around WebXR. First among these is that use of `immersive-vr` mode—which entirely replaces the user's view of the world—requires that the `xr-spatial-tracking` permission policy be in place. On top of that, the document needs to be secure and currently focused. Finally, you must call `requestSession()` from a user event handler, such as the handler for the `click` event.

For more specifics about securing WebXR activities and usage, see the article Permissions and security for WebXR.

### Confirming the session type you need is available

Before trying to create a new WebXR session, it's often wise to first check to see if the user's hardware and software support the presentation mode you wish to use. This can also be used to determine whether to use an immersive or an inline presentation, for example.

To find out if a given mode is supported, call the `XRSystem` method `isSessionSupported()`. This returns a promise which resolves to `true` if the given type of session is available for use or `false` otherwise.

```js
const immersiveOK = await navigator.xr.isSessionSupported("immersive-vr");
if (immersiveOK) {
  // Create and use an immersive VR session
} else {
  // Create an inline session instead, or tell the user about the
  // incompatibility if inline is required
}
```

Creating and starting the session
---------------------------------

A WebXR session is represented by an `XRSession` object. To obtain an `XRSession`, you call your `XRSystem`'s `requestSession()` method, which returns a promise that resolves with an `XRSession` if it's able to establish one successfully. Fundamentally, that looks like this:

```js
xr.requestSession("immersive-vr").then((session) => {
  xrSession = session;
  /\* continue to set up the session \*/
});
```

Note the parameter passed into `requestSession()` in this code snippet: `immersive-vr`. This string specifies the type of WebXR session you want to establish—in this case, a fully-immersive virtual reality experience. There are three options:

`immersive-vr`

A fully-immersive virtual reality session using a headset or similar device that fully replaces the world around the user with the images you present.

`immersive-ar`

An augmented reality session in which images are added to the real world using a headset or similar apparatus. *This option is not yet widely supported, as the AR specification is in flux.*

`inline`

An on-screen presentation of the XR imagery within the context of the document window.

If the session couldn't be created for some reason—such as feature policy disallowing its use or the user declining to grant permission to use the headset—the promise gets rejected. So a more complete function that starts up and returns a WebXR session could look like this:

```js
async function createImmersiveSession(xr) {
  session = await xr.requestSession("immersive-vr");
  return session;
}
```

This function returns the new `XRSession` or throws an exception if an error occurs while creating the session.

### Customizing the session

In addition to the display mode, the `requestSession()` method can take an optional object with initialization parameters to customize the session. Currently, the only configurable aspect of the session is which of the reference spaces should be used to represent the world's coordinate system. You can specify either required or optional reference spaces in order to obtain a session compatible with the reference spaces you need or prefer to use.

For example, if you need an `unbounded` reference space, you can specify that as a required feature in order to ensure that the session you get can use unbounded spaces:

```js
async function createImmersiveSession(xr) {
  session = await xr.requestSession("immersive-vr", {
    requiredFeatures: ["unbounded"],
  });
  return session;
}
```

On the other hand, if you need an *inline* session and would prefer a `local` reference space, you can do this:

```js
async function createInlineSession(xr) {
  session = await xr.requestSession("inline", {
    optionalFeatures: ["local"],
  });
  return session;
}
```

This `createInlineSession()` function will try to create an inline session that's compatible with the `local` reference space. When you're ready to create your reference space, you can try for a local space, and if that fails, fall back to a `viewer` reference space, which all devices are required to support.

### Preparing the new session for use

Once the `requestSession()` method's returned promise successfully resolves, you know you have a usable WebXR session in hand. You can then proceed to prepare the session for use and begin your animations.

The key things you need (or may need) to do in order to finish the configuration of your session include:

* Add handlers for the events you need to watch. This most likely includes the `end` at a minimum, so you can detect when the session is over.
* If you use XR input controllers, watch the `inputsourceschange` event to detect the addition or removal of XR input controllers, and the various select and squeeze action events.
* You may want to watch for the `XRSystem` event `devicechange` so you can be advised when the set of available immersive devices changes.
* Obtain a WebGL context for the canvas into which you intend to render your frames by calling the `HTMLCanvasElement` method `getContext()` on the target context.
* Set up your WebGL data and models and prepare to render the scene.
* Set the WebGL context as the source for the XR system by creating an `XRWebGLLayer` and passing set the value of the session's `renderState` property `baseLayer`.
* Perform calculations for the initial position and scale of your objects as needed.
* Begin the frame rendering cycle.

In basic form, code to do this final setup might look something like this:

```js
async function runSession(session) {
  session.addEventListener("end", onSessionEnd);

  const canvas = document.querySelector("canvas");
  const gl = canvas.getContext("webgl", { xrCompatible: true });

  // Set up WebGL data and such

  const worldData = loadGLPrograms(session, "worlddata.xml");
  if (!worldData) {
    return null;
  }

  // Finish configuring WebGL

  worldData.session.updateRenderState({
    baseLayer: new XRWebGLLayer(worldData.session, gl),
  });

  // Start rendering the scene

  referenceSpace = await worldData.session.requestReferenceSpace("unbounded");
  worldData.referenceSpace = referenceSpace.getOffsetReferenceSpace(
    new XRRigidTransform(
      worldData.playerSpawnPosition,
      worldData.playerSpawnOrientation,
    ),
  );
  worldData.animationFrameRequestID =
    worldData.session.requestAnimationFrame(onDrawFrame);

  return worldData;
}
```

For the purposes of this example, an object named `worldData` gets created to encapsulate data about the world and rendering environment. This includes the `XRSession` itself, all of the data used to render the scene in WebGL, the world reference space, and the ID returned by `requestAnimationFrame()`.

First, a handler for the `end` event is set up. Then the rendering canvas is obtained and a reference to its WebGL context is retrieved, specifying the `xrCompatible` option when calling `getContext()`.

Next, any data and setup needed for the WebGL renderer is performed before then configuring WebGL to use the framebuffer of the WebGL context as its own framebuffer. This is done using the `XRSession` method `updateRenderState()` to set the render state's `baseLayer` to a newly-created `XRWebGLLayer` encapsulating the WebGL context.

### Preparing to render the scene

At this point, the `XRSession` itself has been fully configured, so we can begin rendering. First, we need a reference space within which coordinates for the world will be stated. We can get the initial reference space for the session by calling the `XRSession`'s `requestReferenceSpace()` method. We specify when calling `requestReferenceSpace()` the name of the type of reference space we want; in this case, `unbounded`. You might just as easily specify `local` or `viewer`, depending on your needs.

**Note:** To understand how to select the right reference space for your needs, see Selecting the reference space type.

The reference space returned by `requestReferenceSpace()` places the origin (0, 0, 0) in the center of the space. This is great—if your player's viewpoint starts in the exact center of the world. But most likely, that's not the case at all. If that's so, you call `getOffsetReferenceSpace()` on the initial reference space to create a *new* reference space which offsets the coordinate system so that (0, 0, 0) is located at the position of the viewer, with the orientation likewise shifted to face in the desired direction. The input value into `getOffsetReferenceSpace()` is an `XRRigidTransform` encapsulating the player's position and orientation as specified in the default world coordinates.

With the new reference space in hand and stored into the `worldData` object for safe-keeping, we call the session's `requestAnimationFrame()` method to schedule a callback to be executed when it's time to render the next frame of animation for the WebXR session. The returned value is an ID we can use later to cancel the request if need be, so we save that into `worldData` as well.

In the end, the `worldData` object is returned to the caller to allow the main code to reference the data it needs later. At this point, the setup process is complete and we've entered the rendering stage of our application. To learn more about rendering, see the article Rendering and the WebXR frame animation callback.

### On operational details

Obviously, this was a just an example. You don't need a `worldData` object to store everything; you can store the information you need to maintain any way you want to. You may need different information or have different specific requirements that cause you to do things differently, or in a different order.

Similarly, the specific methodology you use for loading models and other information and setting up your WebGL data—textures, vertex buffers, shaders, and so on—will vary a great deal depending on your needs, what if any frameworks you're using, and the like.

Important session maintenance events
------------------------------------

Over the course of your WebXR session, you may receive any of a number of events which indicate changes to the state of the session, or which let you know about things you need to do to keep the session operating properly.

### Detecting changes to session's visibility state

When the state of the `XRSession`'s visibility changes—such as when the session is hidden or displayed, or when the user has focused another context—the session receives an `visibilitychange` event.

```js
session.onvisibilitychange = (event) => {
  switch (event.session.visibilityState) {
    case "hidden":
      myFrameRate = 10;
      break;
    case "blurred-visible":
      myFrameRate = 30;
      break;
    case "visible":
    default:
      myFrameRate = 60;
      break;
  }
};
```

This example changes a variable `myFrameRate` depending on the visibility state as it changes. Presumably the renderer uses this value to compute how often to render new frames as the animation loop progresses, thus rendering less frequently the more "blurred" the scene becomes.

### Detecting reference space resets

Occasionally, discontinuities or jumps in the native origin may occur while tracking the user's position in the world. The most common scenarios in which this happens are when the user requests a recalibration of their XR device or when a hiccup or glitch occurs in the flow of tracking data received from the XR hardware. These situations cause the native origin to jump abruptly by the distance and directional angle necessary to bring the native origin back into alignment with the user's position and facing direction.

When this happens, a `reset` event is sent to the session's `XRReferenceSpace`. The event's `transform` property is an `XRRigidTransform` detailing the transform needed to realign the native origin.

**Note:** The `reset` event is fired at the `XRReferenceSpace`, not the `XRSession`!

Another common cause for `reset` events is when a bounded reference space (`bounded-floor`) has its geometry as specified by the `XRBoundedReferenceSpace`'s property `boundsGeometry` change.

For more common causes of reference space resets and more details and sample code, see the documentation for the `reset` event.

### Detecting when the available set of WebXR input controls changes

WebXR maintains a list of input controls which is specific to the WebXR system. These devices include things such as the handheld controllers, motion-sensing cameras, motion-sensitive gloves and other feedback devices. When the user connects or disconnects a WebXR controller device, the `inputsourceschange` event is dispatched to the `XRSession`. This is an opportunity to notify the user of the device's availability, begin to monitor it for inputs, offer configuration options, or whatever you need to do with it.

Ending the WebXR session
------------------------

When the user's VR or AR session draws to a close, the session ends. The shutdown of an `XRSession` can happen either due to the session itself deciding it's time to shut down (such as if the user turns off their XR device), because the user has clicked a button to end the session, or some other situation as appropriate for your application.

Here we discuss both how to request a shutdown of the WebXR session and how to detect when the session has ended, whether by your request or otherwise.

### Shutting down the session

To cleanly shut down the WebXR session when you're done with it, you should call the session's `end()` method. This returns a promise you can use to know when the shutdown is complete.

```js
async function shutdownXR(session) {
  if (session) {
    await session.end();

    /\* At this point, WebXR is fully shut down \*/
  }
}
```

When `shutdownXR()` returns to its caller, the WebXR session is fully and safely shut down.

If you have work that must be done when the session ends, such as releasing resources and the like, you should do that work in your `end` event handler rather than in your main code body. That way, you handle the cleanup regardless of whether the shutdown was automatically or manually triggered.

### Detecting when the session has ended

As previously established, you can detect when the WebXR session has ended—whether because you've called its `end()` method, the user turned off their headset, or some sort of irresolvable error occurred in the XR system—by watching for the `end` event to be sent to the `XRSession`.

```js
session.onend = (event) => {
  /\* the session has shut down \*/

  freeResources();
};
```

Here, when the session has ended and the `end` event is received, a `freeResources()` function is called to release the resources previously allocated and/or loaded to handle the XR presentation. By calling `freeResources()` in the `end` event handler, we call it both when the user clicks a button that triggers a shutdown such as by calling the `shutdownXR()` function shown above *and* when the session ends automatically, whether due to an error or some other reason.

See also
--------

* WebXR Device API
* Fundamentals of WebXR
* Spatial tracking in WebXR
* Viewpoints and viewers: Simulating cameras in WebXR
* Using bounded reference spaces
* Inputs and input sources


WebXR application life cycle - Web APIs

WebXR application life cycle
============================

In this guide, we'll get a birds-eye view of what's involved in creating and driving a WebXR application, without diving down to the code level in detail. This serves as preparation for the next few articles in these WebXR guides, which cover starting up and shutting down a WebXR session, geometry, simulating cameras, spatial tracking, and more.

Life cycle outline
------------------

Most applications using WebXR will follow a similar overall design pattern:

1. Check to see if the user's device and browser are both capable of presenting the XR experience you want to provide.
    1. Make sure the WebXR API is available; if `navigator.xr` is undefined, you can assume the user's browser and/or device doesn't support WebXR. If it's not supported, disable any user interface used to activate XR features and abort any attempts to enter XR mode.
    2. Call `navigator.xr.isSessionSupported()`, specifying the WebXR experience mode you want to provide: `inline`, `immersive-vr`, or `immersive-ar`, in order to determine whether or not the type of session you wish to provide is available.
    3. If the session type you want to use is available, provide the appropriate interface to the user to allow them to activate it.
2. When the user requests the activation of WebXR functionality by engaging with the user interface enabled above, request an `XRSession` using the desired mode. This is done by calling `navigator.xr.requestSession()`, again specifying the string indicating the mode you want to enable: `inline`, `immersive-vr`, or `immersive-ar`.
3. If the promise returned by `requestSession()` resolves, use the new `XRSession` to manage the WebXR session for the duration of the WebXR experience. This will involve managing inputs, animations, and rendering.
    1. Call the `XRSession` method `requestAnimationFrame()` to schedule the first frame render for the XR device.
    2. If your scene is complex, you should consider creating a `Worker`—or using one that you've previously created for this purpose—to perform the computations needed for each frame to be rendered. This will reduce the chance that the rendering process will noticeably stall the app.
    3. Each `requestAnimationFrame()` callback should use the information provided about the objects located in the 3D world to render the frame using WebGL.
    4. Each time the callback is invoked, it should call `requestAnimationFrame()` again in order to let the browser know that the callback needs to be run again when it's time to render the next frame.
4. When the time comes (such as when the user exits your app or navigates away from your site), end the XR session; otherwise, continue the loop until the user chooses to exit XR mode.
    1. To end the XR session yourself, call `XRSession.end()`.
    2. Include a handler for the `XRSession` event `end` event to be informed when the session is ending, regardless of whether your code, the user, or the browser initiated the termination of the session.


A perspective retrospective for WebXR developers - Web APIs

A perspective retrospective for WebXR developers
================================================

Because WebXR uses WebGL to render the views that form the 3D environment displayed using the XR hardware, it's easy to think that the perspective-related matters are identical to those found in any WebGL project. This is largely true, but there are a few specific topics that need to be revisited and some minor additional guidelines considered in order to ensure that your app looks right and, more importantly, that your 3D world doesn't cause people to become ill from vertigo or other effects that can be caused when what's being seen doesn't match what the brain expects from reality.

In this article, we examine scenarios in which the way your project calculates, applies, and thinks about perspective may differ from code written for non-XR applications.

Viewing frustum frustrations
----------------------------

Every WebXR session, represented by an `XRSession` object, offers a set of options that can be configured by creating a new `XRRenderState` object and activating the updated state by calling the session's `updateRenderState()` method to replace the current configuration.

The majority of these values define the XR device's viewing frustum; that is, the subset of the device's visual field that should be rendered. The viewing frustum can be represented using four key data points: the field of view angle, the aspect ratio of the rendered image, and the distances to the near and far clipping planes.

### Welcome to the projection matrix

Most of the time, the projection model you'll use is the perspective projection model, so its projection matrix is called the **perspective projection matrix**. This matrix is used to map each pixel from the 3D virtual world to a point in the 2D backbuffer for the view being rendered.

Under typical circumstances, you can and should get the perspective projection matrix directly from the view you're rendering. The `XRView` object's `projectionMatrix` property holds the projection matrix representing the view's perspective, and should almost always be used without alteration. Changes made to the projection matrix provided by the `XRView` are likely to result in distortion or poor alignment of the rendered content relative to the real-world scenery; this could be significant enough to cause virtual reality sickness in at least some of your users.

For example, if your app uses a WebGL uniform named `uProjectionMatrix` to pass the projection matrix to your shaders, you might use code like this to pass the projection matrix for the `view` currently being rendered:

```js
gl.uniformMatrix4fv(uProjectionMatrix, false, view.projectionMatrix);
```

### Customizing the projection matrix

Although normally you should avoid manually building or altering the projection matrix provided by the view, you can do so in some situations. The most common reason it may make sense to do this is to alter the near and far clipping plane distances to increase or reduce the number of polygons to be rendered, for performance reasons. When games offer preferences to adjust the viewing distance, that is done by changing these plane distance values.

In immersive mode, the WebXR system obtains the default viewing frustum from the software provided by the hardware vendor. This viewing frustum is based on some combination of the device's lenses, display hardware, and cameras. Everything from the size of the imaging sensor to the focal length of the lens is involved in this calculation.

Immersive experiences use hardware-defined fields of view, focal lengths, and so forth, so when using an immersive session, you can only change the near and far clipping distances. This is done by setting the values of the `XRRenderState` properties `depthNear` and `depthFar`.

In inline mode, you can also change the field of view directly by setting the value of the `renderState`'s `inlineVerticalFieldOfView` property. This property needs to be set to `null` for any immersive session.

Once you have the viewing frustum, you can compute the perspective projection matrix that WebGL uses when rendering the scene using a function like this:

```js
function makePerspectiveMatrix(fieldOfViewInRadians, aspectRatio, near, far) {
  const f = 1.0 / Math.tan(fieldOfViewInRadians / 2);
  const rangeInv = 1 / (near - far);

  return [
    f / aspectRatio,
    0,
    0,
    0,
    0,
    f,
    0,
    0,
    0,
    0,
    (near + far) \* rangeInv,
    -1,
    0,
    0,
    near \* far \* rangeInv \* 2,
    0,
  ];
}
```

The values of `near` and `far` are obtained directly from the frustum; they're the distance from the origin to the closest point on the near clipping plane and the far clipping plane, respectively. The aspect ratio is the value obtained by dividing the width of the field of view by its height. If the target display uses a 16:9 aspect ratio, the value used for `aspectRatio` should be `16/9`, or 1.7777777778.

If you're using a library or framework that provides matrix math functions, it will almost certainly have a similar function include. For example, in the popular glMatrix library, you'll find this in the function `mat4.perspective()`.

Regardless of where it comes from, once you have the projection matrix, you can use it when calling WebGL to render your scene.

Aligning with reality
---------------------

In augmented reality (AR) applications, the contents you render are overlaid atop the real world. To do this well, your perspective calculations need to match the viewer's perspective of the world around them. If you don't, your objects won't correctly align with reality.

If your virtual camera's perspective projection matrix doesn't result in virtual objects having the same apparent perspective as the real world, the disjunction between the virtual and physical worlds could be jarring or, even worse, induce vertigo, motion sickness, or other forms of discomfort in your app's users.

A related issue is that if you use your perspective matrix to determine where to place objects, a mismatch between your perspective projection matrix and the user's physical perspective on the world could result in the objects not being positioned accurately. If your app lets the user hang virtual paintings on their walls, for example, but the perspective matrix doesn't match up, the placed paintings could wind up not actually up against the wall, partially intersecting the wall, or with one end closer to the wall than the other instead of being properly parallel to the wall.

See also
--------

* WebGL model view projection
* Viewpoints and viewers: Simulating cameras in WebXR


WebXR performance guide - Web APIs

WebXR performance guide
=======================

WebXR applications involve multiple technologies which can be highly sensitive to performance constraints. As such, you may find yourself needing to make adjustments or compromises to optimize the performance of your WebXR application to be as usable as possible on the broadest assortment of target devices. In this guide, we'll examine a variety of suggestions and recommendations that will help you make your WebXR app as performant as possible.

Rendering tips
--------------

Talk about general stuff like limiting how many different loops there are during rendering, avoiding unnecessary drawing, etc.

Can probably also include stuff from this explainer in the spec repo

Managing rendering quality
--------------------------

This section will come in part from this explainer in the spec repo

Managing frame rate
-------------------

Content about frame rate management.

Managing use of depth
---------------------

This section will combine information from this explainer and this one, in the spec repository.

Optimizing memory use
---------------------

When using libraries that perform things such as matrix mathematics, you typically have a number of working variables through which various vectors, matrices, and quaternions pass over time. It makes sense, then, to have a limited set of these objects, replacing their contents with the new information each time you need to use them. They can be thought of as being similar to the registers in a microprocessor: a limited set of memory storage slots for specific kinds of data or use cases.

While an individual vector or matrix doesn't occupy an inordinate amount of memory, the sheer number of vectors and matrices and other structures that are used to build each frame of a 3D scene means the memory management becomes a problem eventually if you keep allocating and de-allocating memory objects.

Consider the following

```js
function drawScene(gl, view, programInfo, buffers, texture, deltaTime) {
  // …
  for (const object in scene) {
    const vertexList = [
      /\* … \*/
    ];
    const normalMatrix = mat4.create();
    const modelViewMatrix = mat4.create();
    const objectMatrix = mat4.create();

    // Apply rotation updates to the object if needed

    mat4.rotate(/\* … \*/);
  }
}
```

This renders a scene. But it's inefficient, because it allocates as local variables a number of things, including at least two matrices, an array of vertices, and more. That means that for every frame, the JavaScript runtime has to allocate memory for those and set them up—possibly triggering garbage collection—and then when each interaction of the loop is completed, the memory is released.

A simple change can optimize this significantly:

```js
const vertexList = [
  /\* … \*/
];
const normalMatrix = mat4.create();
const modelViewMatrix = mat4.create();

function drawScene(gl, view, programInfo, buffers, texture, deltaTime) {
  // …
  for (const object in scene) {
    // …
  }
}
```

Now, instead of allocating variables every loop iteration, we're using global constants(or class member constants). This has multiple benefits:

* The memory allocated for each value or structure will not need to be reallocated every frame. This reduces the potential for triggering garbage collection, and optimizes memory use.
* You can't accidentally delete the objects that contain your vectors and matrices, since they're constants.
* You can, however, still replace the *contents* of each of these objects, so they're reusable.

You're now protected from several possible coding mistakes, and your entire animation will be smoother and more performant as well.


Targeting and hit detection - Web APIs

Targeting and hit detection
===========================

Virtual object hit testing
--------------------------

Detection of collisions with virtual objects usually doesn't actually involve testing for intersection of the ray with one of the scene's polygons, as a typical scene may have hundreds or thousands of polygons, which makes direct tracing of rays to polygons impractical in most cases. Instead, most applications find a way to simplify the implementation of their hit testing algorithms.

It's possible—or even likely—that whatever 3D graphics engine you're using offers hit testing, especially if it's designed specifically for game development.

### Simplified representative objects

One common solution is to overlay simplified, invisible objects atop the objects in your scene. These objects then serve a s. For instance, if you have a more-or-less rectangular object, use a rectangle as a surrogate for the object when performing hit testing. Likewise, if an object is essentially round, use the radius of the minimum enclosing circle to establish a collision test object.

Real-world hit testing
----------------------

The acronym "LIDAR" has multiple definitions depending on specifics of how it's implemented, but the end result is the same. Most commonly, it refers to "*Laser Imaging, Detection, And Ranging*" or "*LIght Detection and Ranging*").

Testing for collisions with the real world is a different problem, which may involve not only interpreting the imagery from the device's camera (if available) but also potentially multiple additional sensors. Some devices include infrared sensors to help range objects, and others provide powerful LIDAR systems, which use lasers (usually infrared lasers, which can't be seen by the human eye) to determine range to objects in the world.

The details of how to work with an individual platform's ranging system is beyond the scope of this article. However, there's hope: a proposal has been floated for a WebXR Hit Test Module that would layer atop WebXR to provide an API for performing hit testing and collision detection.

See also
--------

* 3D collision detection
* HTML5 games: 3D collision detection (Hacks blog)


WebTransportBidirectionalStream: readable property - Web APIs

WebTransportBidirectionalStream: readable property
==================================================

Limited availability
--------------------

This feature is not Baseline because it does not work in some of the most widely-used browsers.

* Learn more
* See full compatibility
* Report feedback
The **`readable`** read-only property of the `WebTransportBidirectionalStream` interface returns a `WebTransportReceiveStream` instance that can be used to reliably read incoming data.

**Note:** This feature is available in Web Workers

Value
-----

A `WebTransportReceiveStream`.

Examples
--------

See the main `WebTransportBidirectionalStream` interface page.

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

| Specification |
| --- |
| WebTransport # dom-webtransportbidirectionalstream-readable |

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

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

See also
--------

* Using WebTransport
* WebSockets API
* Streams API
* WebTransport over HTTP/3


WebTransportBidirectionalStream: writable property - Web APIs

WebTransportBidirectionalStream: writable property
==================================================

Limited availability
--------------------

This feature is not Baseline because it does not work in some of the most widely-used browsers.

* Learn more
* See full compatibility
* Report feedback
The **`writable`** read-only property of the `WebTransportBidirectionalStream` interface returns a `WebTransportSendStream` instance that can be used to write outgoing data.

**Note:** This feature is available in Web Workers

Value
-----

A `WebTransportSendStream`.

Examples
--------

See the main `WebTransportBidirectionalStream` interface page.

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

| Specification |
| --- |
| WebTransport # dom-webtransportbidirectionalstream-writable |

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

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

See also
--------

* Using WebTransport
* WebSockets API
* Streams API
* WebTransport over HTTP/3


XPathException: code property - Web APIs

XPathException: code property
=============================

**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.

 The **`code`** read-only property of the
 `XPathException` interface returns a `short` that contains one
 of the error code constants.

Value
-----

A `short` number representing the error code.

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

#### No specification found

No specification data found for `api.XPathException.code`.
Check for problems with this page or contribute a missing `spec_url` to mdn/browser-compat-data. Also make sure the specification is included in w3c/browser-specs.

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

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


Node: textContent property - Web APIs

Node: textContent property
==========================

 The **`textContent`** property of the `Node`
 interface represents the text content of the node and its descendants.

**Note:** `textContent` and `HTMLElement.innerText` are easily confused,
 but the two properties are different in important ways.

Value
-----

A string, or `null`. Its value depends on the situation:

* If the node is a `document` or a doctype,
 `textContent` returns `null`.

**Note:** To get *all* of the text and CDATA data for the whole
 document, use `document.documentElement.textContent`.
* If the node is a CDATA section,
 a comment, a processing instruction,
 or a text node,
 `textContent` returns, or sets, the text inside the node,
 i.e., the `Node.nodeValue`.
* For other node types, `textContent` returns the concatenation of the
 `textContent` of every child node, excluding comments and processing
 instructions. (This is an empty string if the node has no children.)

**Warning:** Setting `textContent` on a node removes *all* of the node's children
 and replaces them with a single text node with the given string value.

### Differences from innerText

 Don't get confused by the differences between `Node.textContent` and
 `HTMLElement.innerText`. Although the names seem similar, there are
 important differences:

* `textContent` gets the content of *all* elements, including
 `<script>` and `<style>` elements. In contrast,
 `innerText` only shows "human-readable" elements.
* `textContent` returns every element in the node. In contrast,
 `innerText` is aware of styling and won't return the text of "hidden"
 elements.
    + Moreover, since `innerText` takes CSS styles into account,
     reading the value of `innerText` triggers a
     reflow to ensure up-to-date computed styles. (Reflows can
     be computationally expensive, and thus should be avoided when possible.)
### Differences from innerHTML

`Element.innerHTML` returns HTML, as its name indicates. Sometimes people
 use `innerHTML` to retrieve or write text inside an element, but
 `textContent` has better performance because its value is not parsed as
 HTML.

Moreover, using `textContent` can prevent XSS attacks.

Examples
--------

Start with this HTML fragment.

```html
<div id="divA">This is <span>some</span> text!</div>
```

You can use `textContent` to get the element's text content:

```js
let text = document.getElementById("divA").textContent;
// The text variable is now: 'This is some text!'
```

If you prefer to set the element's text content, you can do:

```js
document.getElementById("divA").textContent = "This text is different!";
// The HTML for divA is now:
// <div id="divA">This text is different!</div>
```

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

| Specification |
| --- |
| DOM Standard # dom-node-textcontent |

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

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

See also
--------

* `HTMLElement.innerText`
* `Element.innerHTML`
* More on differences between `innerText` and `textContent`
 (blog post)


Node: lastChild property - Web APIs

Node: lastChild property
========================

 The read-only **`lastChild`** property of the `Node` interface
 returns the last child of the node, or `null` if there are no child nodes.

**Note:** This property returns any type of node that is the last child of this one.
 It may be a `Text` or a `Comment` node.
 If you want to get the last `Element` that is a child of another element,
 consider using `Element.lastElementChild`.

Value
-----

A `Node` that is the last child of the node, or `null` is there are no child nodes.

Example
-------

```js
const tr = document.getElementById("row1");
const corner_td = tr.lastChild;
```

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-lastchild① |

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

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

See also
--------

* `Node.firstChild`
* `Element.lastElementChild`


Node: nodeName property - Web APIs

Node: nodeName property
=======================

The read-only **`nodeName`** property of `Node` returns the name of the current node as a string.

Value
-----

A string. Values for the different types of nodes are:

`Attr`

The value of `Attr.name`, that is the *qualified name* of the attribute.

`CDATASection`

The string `"#cdata-section"`.

`Comment`

The string `"#comment"`.

`Document`

The string `"#document"`.

`DocumentFragment`

The string `"#document-fragment"`.

`DocumentType`

The value of `DocumentType.name`

`Element`

 The value of `Element.tagName`, that is the *uppercase* name of the element tag if an HTML element,
 or the *lowercase* element tag if an XML element (like a SVG or MATHML element).

`ProcessingInstruction`

The value of `ProcessingInstruction.target`

`Text`

The string `"#text"`.

Example
-------

This example displays the node names of several nodes

```html
This is some HTML:
<div id="d1">Hello world</div>
<!-- Example of comment -->
Text <span>Text</span> Text<br />
<svg height="20" width="20">
  <circle cx="10" cy="10" r="5" stroke="black" stroke-width="1" fill="red" />
</svg>
<hr />
<output id="result">Not calculated yet.</output>
```

and the following script:

```js
let node = document.querySelector("body").firstChild;
let result = "Node names are:<br/>";
while (node) {
  result += `${node.nodeName}<br/>`;
  node = node.nextSibling;
}

const output = document.getElementById("result");
output.innerHTML = result;
```

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-nodename① |

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

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

See also
--------

* `Element.tagName`
* `Attr.name`
* `DocumentType.name`
* `ProcessingInstruction.target`


Node: replaceChild() method - Web APIs

Node: replaceChild() method
===========================

The **`replaceChild()`** method of the `Node` interface replaces a child node within the given (parent) node.

Syntax
------

```js
replaceChild(newChild, oldChild)
```

### Parameters

`newChild`

The new node to replace `oldChild`.

**Warning:** If the new node is already present somewhere else in the DOM, it is first removed from that position.

`oldChild`

The child to be replaced.

**Note:** The parameter order, *new* before *old*, is unusual.
 `Element.replaceWith()`, applying only to nodes that are elements,
 may be easier to read and use.

### Return value

The replaced `Node`. This is the same node as `oldChild`.

### Exceptions

`HierarchyRequestError` `DOMException`

Thrown when the constraints of the DOM tree are violated, that is if one of the following cases occurs:

* If the parent of `oldChild` is not a `Document`, `DocumentFragment`, or an `Element`.
* If the replacement of `oldChild` by `newChild` would lead to a cycle, that is if `newChild` is an ancestor of the node.
* If `newChild` is not a `DocumentFragment`, a `DocumentType`, an `Element`, or a `CharacterData`.
* If the current node is a `Text`, and its parent is a `Document`.
* If the current node is a `DocumentType` and its parent is *not* a `Document`, as a *doctype* should always be a direct descendant of a *document*.
* If the parent of the node is a `Document` and `newChild` is a `DocumentFragment` with more than one `Element` child, or that has a `Text` child.
* If the replacement of `oldChild` by `newChild` would lead to `Document` with more than one `Element` as child.
* If the replacement of `oldChild` by `newChild` would lead to the presence of an `Element` node before a `DocumentType` node.

`NotFoundError` `DOMException`

Thrown if the parent of `oldChild` is not the current node.

Example
-------

```js
// Given:
// <div>
// <span id="childSpan">foo bar</span>
// </div>

// Create an empty element node
// without an ID, any attributes, or any content
const sp1 = document.createElement("span");

// Give it an id attribute called 'newSpan'
sp1.id = "newSpan";

// Create some content for the new element.
const sp1_content = document.createTextNode("new replacement span element.");

// Apply that content to the new element
sp1.appendChild(sp1_content);

// Build a reference to the existing node to be replaced
const sp2 = document.getElementById("childSpan");
const parentDiv = sp2.parentNode;

// Replace existing node sp2 with the new span element sp1
parentDiv.replaceChild(sp1, sp2);

// Result:
// <div>
// <span id="newSpan">new replacement span element.</span>
// </div>
```

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

| Specification |
| --- |
| DOM Standard # dom-node-replacechild |

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

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

See also
--------

* `Node.removeChild`
* `Element.replaceWith`


Node: selectstart event - Web APIs

Node: selectstart event
=======================

The **`selectstart`** event of the Selection API is fired when a user starts a new selection.

If the event is canceled, the selection is not changed.

Syntax
------

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

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

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

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

A generic `Event`.

Examples
--------

```js
// addEventListener version
document.addEventListener("selectstart", () => {
  console.log("Selection started");
});

// onselectstart version
document.onselectstart = () => {
  console.log("Selection started.");
};
```

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

| Specification |
| --- |
| Selection API # selectstart-event |
| Selection API # dom-globaleventhandlers-onselectstart |

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

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

See also
--------

* `selectionchange`


Node: isDefaultNamespace() method - Web APIs

Node: isDefaultNamespace() method
=================================

 The **`isDefaultNamespace()`** method of the `Node` interface accepts a namespace URI as an argument.
 It returns a boolean value that is `true` if the namespace is the default namespace on the given node and `false` if not.

**Note:** The default namespace of an HTML element is always `""`. For a SVG element, it is set by the `xmlns` attribute.

Syntax
------

```js
isDefaultNamespace(namespaceURI)
```

### Parameters

`namespaceURI`

A string representing the namespace against which the element will be checked.

**Note:** `namespaceURI` is not an optional parameter, but can be `null`.

### Return value

A boolean value that holds the return value `true` or `false`, indicating if the parameter is the default namespace, or not.

Example
-------

```html
Is "" the default namespace for <output>:
<output>Not tested</output>.<br />
Is "http://www.w3.org/2000/svg" the default namespace for <output>:
<output>Not tested</output>.<br />
Is "" the default namespace for <svg>: <output>Not tested</output>.<br />
Is "http://www.w3.org/2000/svg" the default namespace for <svg>:
<output>Not tested</output>.<br />
<svg xmlns="http://www.w3.org/2000/svg" height="1"></svg>
<button>Click to run tests</button>
```

```js
const button = document.querySelector("button");
button.addEventListener("click", () => {
  const aHtmlElt = document.querySelector("output");
  const aSvgElt = document.querySelector("svg");

  const result = document.getElementsByTagName("output");
  result[0].value = aHtmlElt.isDefaultNamespace(""); // true
  result[1].value = aHtmlElt.isDefaultNamespace("http://www.w3.org/2000/svg"); // false
  result[2].value = aSvgElt.isDefaultNamespace(""); // false
  result[3].value = aSvgElt.isDefaultNamespace("http://www.w3.org/2000/svg"); // true
});
```

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

| Specification |
| --- |
| DOM Standard # dom-node-isdefaultnamespace |

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

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

See also
--------

* `Node.lookupNamespaceURI`
* `Node.lookupPrefix`


Node: parentNode property - Web APIs

Node: parentNode property
=========================

 The read-only **`parentNode`** property of the `Node` interface
 returns the parent of the specified node in the DOM tree.

`Document` and `DocumentFragment` nodes can never have a parent, so
 `parentNode` will always return `null`.
 It also returns `null` if the node has just been created
 and is not yet attached to the tree.

Value
-----

 A `Node` that is the parent of the current node. The parent of an element is
 an `Element` node, a `Document` node, or a `DocumentFragment` node.

Example
-------

```js
if (node.parentNode) {
  // remove a node from the tree, unless
  // it's not in the tree already
  node.parentNode.removeChild(node);
}
```

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-parentnode① |

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

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

See also
--------

* `Node.firstChild`
* `Node.lastChild`
* `Node.childNodes`
* `Node.nextSibling`
* `Node.parentElement`
* `Node.previousSibling`
* `Node.removeChild`


Node: baseURI property - Web APIs

Node: baseURI property
======================

 The read-only **`baseURI`** property of the `Node` interface
 returns the absolute base URL of the document containing the node.

The base URL is used to resolve relative URLs when the browser needs to obtain an absolute URL, for example when processing the HTML `<img>` element's `src` attribute or the `xlink:href`
Deprecated
 or `href` attributes in SVG.

 Although this property is read-only, its value is determined by an algorithm each time
 the property is accessed, and may change if the conditions changed.

The base URL is determined as follows:

1. By default, the base URL is the location of the document (as determined by `window.location`).
2. If it is an HTML Document and there is a `<base>` element in the document,
 the `href` value of the *first* `Base` element with such an attribute is used instead.
Value
-----

A string representing the base URL of the `Node`.

Examples
--------

### Without <base>

```html
<output>Not calculated</output>
```

```js
const output = document.querySelector("output");
output.value = output.baseURI;
```

### With <base>

```html
<base href="https://developer.mozilla.org/modified\_base\_uri/" />
<output>Not calculated</output>
```

```js
const output = document.querySelector("output");
output.value = output.baseURI;
```

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-baseuri① |

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

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

See also
--------

* `<base>` element.


Node: nodeType property - Web APIs

Node: nodeType property
=======================

 The read-only **`nodeType`** property of a `Node` interface is an integer
 that identifies what the node is. It distinguishes different kind of nodes from each other,
 such as `elements`, `text` and `comments`.

Value
-----

An integer which specifies the type of the node. Possible values are:

`Node.ELEMENT_NODE` (`1`)

An `Element` node like `<p>` or `<div>`.

`Node.ATTRIBUTE_NODE` (`2`)

An `Attribute` of an `Element`.

`Node.TEXT_NODE` (`3`)

The actual `Text` inside an `Element` or `Attr`.

`Node.CDATA_SECTION_NODE`(`4`)

A `CDATASection`, such as `<!CDATA[[ … ]]>`

`Node.PROCESSING_INSTRUCTION_NODE` (`7`)

A `ProcessingInstruction` of an XML document, such as `<?xml-stylesheet … ?>`.

`Node.COMMENT_NODE` (`8`)

A `Comment` node, such as `<!-- … -->`.

`Node.DOCUMENT_NODE` (`9`)

A `Document` node.

`Node.DOCUMENT_TYPE_NODE` (`10`)

A `DocumentType` node, such as `<!DOCTYPE html>`.

`Node.DOCUMENT_FRAGMENT_NODE` (`11`)

A `DocumentFragment` node.

 The following constants have been deprecated and are not in use anymore: `Node.ENTITY_REFERENCE_NODE` (`5`),
 `Node.ENTITY_NODE` (`6`), and `Node.NOTATION_NODE` (`12`).

Examples
--------

### Different types of nodes

```js
document.nodeType === Node.DOCUMENT\_NODE; // true
document.doctype.nodeType === Node.DOCUMENT\_TYPE\_NODE; // true

document.createDocumentFragment().nodeType === Node.DOCUMENT\_FRAGMENT\_NODE; // true

const p = document.createElement("p");
p.textContent = "Once upon a time…";

p.nodeType === Node.ELEMENT\_NODE; // true
p.firstChild.nodeType === Node.TEXT\_NODE; // true
```

### Comments

 This example checks if the first node inside the document element is a comment, and
 displays a message if not.

```js
const node = document.documentElement.firstChild;
if (node.nodeType !== Node.COMMENT\_NODE) {
  console.warn("You should comment your code!");
}
```

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-nodetype① |

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

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


Node: childNodes property - Web APIs

Node: childNodes property
=========================

 The read-only **`childNodes`** property of the `Node` interface returns a live
 `NodeList` of child `nodes` of the given element where
 the first child node is assigned index `0`. Child nodes include elements, text and
 comments.

**Note:** The `NodeList` being live means that its content is changed each time
 new children are added or removed.

 Browsers insert text nodes into a document to represent whitespace in the source markup.
 Therefore a node obtained, for example, using `Node.childNodes[0]`
 may refer to a whitespace text node rather than the actual element the author intended to get.

See Whitespace in the DOM for more information.

 The items in the collection of nodes are objects, not strings. To get data from node
 objects, use their properties. For example, to get the name of the first
 childNode, you can use `elementNodeReference.childNodes[0].nodeName`.

 The `document` object itself has two children: the Doctype declaration and the
 root element, typically referred to as `documentElement`. In HTML
 documents the latter is the `<html>` element.

 It is important to keep in mind that `childNodes` includes *all* child nodes,
 including non-element nodes like text and comment.
 To get a collection containing only elements, use `Element.children` instead.

Value
-----

A live `NodeList` containing the children of the node.

**Note:** Several calls to `childNodes` return the *same* `NodeList`.

Examples
--------

### Simple usage

```js
// Note that parg is an object reference to a <p> element

// First check that the element has child nodes
if (parg.hasChildNodes()) {
  let children = parg.childNodes;

  for (const node of children) {
    // Do something with each child as children[i]
    // NOTE: List is live! Adding or removing children will change the list's `length`
  }
}
```

### Remove all children from a node

```js
// This is one way to remove all children from a node
// box is an object reference to an element
while (box.firstChild) {
  // The list is LIVE so it will re-index each call
  box.removeChild(box.firstChild);
}
```

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-childnodes① |

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

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

See also
--------

* `Node.firstChild`
* `Node.lastChild`
* `Node.nextSibling`
* `Node.previousSibling`
* `Element.children`


Node: previousSibling property - Web APIs

Node: previousSibling property
==============================

 The read-only **`previousSibling`** property of the `Node` interface
 returns the node immediately preceding the specified one in its parent's
 `childNodes` list,
 or `null` if the specified node is the first in that list.

**Note:** Browsers insert text nodes into a document to represent whitespace in the source markup.
 Therefore a node obtained, for example, using `Node.firstChild`
 or `Node.previousSibling`
 may refer to a whitespace text node rather than the actual element the author intended to get.

See Whitespace in the DOM for more information.

 You can use `previousElementSibling`
 to get the previous element node (skipping text nodes and any other non-element nodes).

To navigate the opposite way through the child nodes list use Node.nextSibling.

Value
-----

 A `Node` representing the previous sibling of the current node,
 or `null` if there are none.

Examples
--------

The following examples demonstrate how `previousSibling` works with and without text nodes mixed in with elements.

### First example

In this example, we have a series of `img` elements directly adjacent to each other, with no whitespace between them.

```html
<img id="b0" /><img id="b1" /><img id="b2" />
```

```js
document.getElementById("b1").previousSibling; // <img id="b0">
document.getElementById("b2").previousSibling.id; // "b1"
```

### Second example

In this example, there are whitespace text nodes (line breaks) between the `img` elements.

```html
<img id="b0" />
<img id="b1" />
<img id="b2" />
```

```js
document.getElementById("b1").previousSibling; // #text
document.getElementById("b1").previousSibling.previousSibling; // <img id="b0">
document.getElementById("b2").previousSibling.previousSibling; // <img id="b1">
document.getElementById("b2").previousSibling; // #text
document.getElementById("b2").previousSibling.id; // undefined
```

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-previoussibling① |

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

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

See also
--------

* `Node.nextSibling`
* `Element.previousElementSibling`


Node: firstChild property - Web APIs

Node: firstChild property
=========================

 The read-only **`firstChild`** property of the `Node` interface
 returns the node's first child in the tree,
 or `null` if the node has no children.

 If the node is a `Document`,
 this property returns the first node in the list of its direct children.

**Note:** This property returns any type of node that is the first child of this one.
 It may be a `Text` or a `Comment` node.
 If you want to get the first `Element` that is a child of another element,
 consider using `Element.firstElementChild`.

Value
-----

A `Node`, or `null` if there are none.

Example
-------

 This example demonstrates the use of `firstChild` and how whitespace nodes
 might interfere with using this property.

```html
<p id="para-01">
  <span>First span</span>
</p>

<script>
 const p01 = document.getElementById("para-01");
 console.log(p01.firstChild.nodeName);
</script>
```

 In the above, the console will show '#text'
 because a text node is inserted to maintain the whitespace between the end of the
 opening `<p>` and `<span>` tags. **Any**
whitespace
 will create a `#text` node, from a single space to multiple spaces, returns,
 tabs, and so on.

 Another `#text` node is inserted between the closing
 `</span>` and `</p>` tags.

 If this whitespace is removed from the source, the #text nodes are not inserted and the
 span element becomes the paragraph's first child.

```html
<p id="para-01"><span>First span</span></p>

<script>
 const p01 = document.getElementById("para-01");
 console.log(p01.firstChild.nodeName);
</script>
```

Now the console will show 'SPAN'.

 To avoid the issue with `node.firstChild` returning `#text` or
 `#comment` nodes, `Element.firstElementChild` can be used to
 return only the first element node.

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-firstchild① |

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

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

See also
--------

* `Element.firstElementChild`
* `Node.lastChild`


Node: lookupNamespaceURI() method - Web APIs

Node: lookupNamespaceURI() method
=================================

 The **`lookupNamespaceURI()`** method of the `Node` interface
 takes a prefix as parameter and returns the namespace URI associated with it on the given node if found (and
 `null` if not).

Syntax
------

```js
lookupNamespaceURI(prefix)
```

### Parameters

`prefix`

The prefix to look for.

**Note:** This parameter is not optional, but can be set to `null`.

### Return value

 A string containing the namespace URI corresponding to the prefix.
 If the prefix is not found, it returns `null`.
 If the requested `prefix` is `null`, it returns the default namespace URI.

Example
-------

```html
Namespace URL for <code>xlink</code> on <output>:
<output>Not tested</output>.<br />
Namespace URL for <code>xml</code> on <output>:
<output>Not tested</output>.<br />
Namespace URL for <code>html</code> on <output>:
<output>Not tested</output>.<br />
Namespace URL for <code>``</code> on <output>:
<output>Not tested</output>.<br />
Namespace URL for <code>svg</code> on <svg>:
<output>Not tested</output>.<br />
Namespace URL for <code>xlink</code> on <svg>:
<output>Not tested</output>.<br />
Namespace URL for <code>xml</code> on <svg>:
<output>Not tested</output>.<br />
<svg xmlns:svg="http://www.w3.org/2000/svg" height="1"></svg>
<button>Click to see the results</button>
```

```js
const button = document.querySelector("button");
button.addEventListener("click", () => {
  const aHtmlElt = document.querySelector("output");
  const aSvgElt = document.querySelector("svg");

  const result = document.getElementsByTagName("output");
  result[0].value = aHtmlElt.lookupNamespaceURI("xlink");
  result[1].value = aHtmlElt.lookupNamespaceURI("xml");
  result[2].value = aHtmlElt.lookupNamespaceURI("html");
  result[3].value = aHtmlElt.lookupNamespaceURI("");
  result[4].value = aSvgElt.lookupNamespaceURI("svg");
  result[5].value = aSvgElt.lookupNamespaceURI("xlink");
  result[6].value = aSvgElt.lookupNamespaceURI("xml");
});
```

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

| Specification |
| --- |
| DOM Standard # dom-node-lookupnamespaceuri |

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

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

See also
--------

* `Node.lookupPrefix`
* `Node.isDefaultNameSpace`


Node: lookupPrefix() method - Web APIs

Node: lookupPrefix() method
===========================

 The **`lookupPrefix()`** method of the `Node` interface
 returns a string containing the prefix for a given namespace URI, if present,
 and `null` if not.
 When multiple prefixes are possible, the first prefix is returned.

Syntax
------

```js
lookupPrefix(namespace)
```

### Parameters

`namespace`

A string containing the namespace to look the prefix up.

**Note:** This parameter is not optional but can be set to `null`.

### Return value

 A string containing the corresponding prefix, or `null` if none has been found.
 If `namespace` is null, or the empty string, `lookupPrefix()` returns `null`.

 If the node is a `DocumentType` or a `DocumentFragment`,
 `lookupPrefix()` always returns `null`.

Example
-------

```html
Prefix for <code>http://www.w3.org/2000/svg</code> on <output>:
<output>Not tested</output>.<br />
Prefix for <code>http://www.w3.org/XML/1998/namespace</code> on <output>:
<output>Not tested</output>.<br />
Prefix for <code>http://www.w3.org/TR/html4/</code> on <output>:
<output>Not tested</output>.<br />
Prefix for <code>https://www.w3.org/1999/xlink</code> on <output>:
<output>Not tested</output>.<br />
Prefix for <code>http://www.w3.org/2000/svg</code> on <svg>:
<output>Not tested</output>.<br />
Prefix for <code>https://www.w3.org/1999/xlink</code> on <svg>:
<output>Not tested</output>.<br />
Prefix for <code>http://www.w3.org/XML/1998/namespace</code> on <svg>:
<output>Not tested</output>.<br />
<svg xmlns:t="http://www.w3.org/2000/svg" height="1"></svg>
<button>Click to see the results</button>
```

```js
const button = document.querySelector("button");
button.addEventListener("click", () => {
  const aHtmlElt = document.querySelector("output");
  const aSvgElt = document.querySelector("svg");

  const result = document.getElementsByTagName("output");
  result[0].value = aHtmlElt.lookupPrefix("http://www.w3.org/2000/svg"); // true
  result[1].value = aHtmlElt.lookupPrefix(
    "http://www.w3.org/XML/1998/namespace",
  ); // false
  result[2].value = aHtmlElt.lookupPrefix("http://www.w3.org/TR/html4/"); // true
  result[3].value = aHtmlElt.lookupPrefix("https://www.w3.org/1999/xlink"); // false
  result[4].value = aSvgElt.lookupPrefix("http://www.w3.org/2000/svg"); // true
  result[5].value = aSvgElt.lookupPrefix("https://www.w3.org/1999/xlink"); // true
  result[6].value = aSvgElt.lookupPrefix(
    "http://www.w3.org/XML/1998/namespace",
  ); // false
});
```

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

| Specification |
| --- |
| DOM Standard # dom-node-lookupprefix |

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

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

See also
--------

* http://www.w3.org/TR/DOM-Level-3-Cor...amespacePrefix


Node: isEqualNode() method - Web APIs

Node: isEqualNode() method
==========================

 The **`isEqualNode()`** method of the `Node` interface tests whether two nodes are equal.
 Two nodes are equal when they have the same type, defining characteristics (for
 elements, this would be their ID, number of children, and so forth), its attributes
 match, and so on. The specific set of data points that must match varies depending on
 the types of the nodes.

Syntax
------

```js
isEqualNode(otherNode)
```

### Parameters

`otherNode`

The `Node` to compare equality with.

**Note:** This parameter is not optional, but can be set to `null`.

### Return value

 A boolean value that is `true` if the two nodes are equals, or `false` if not.
 If `otherNode` is `null`, `isEqualNode()` always return false.

Example
-------

 In this example, we create three `<div>` blocks. The first and third
 have the same contents and attributes, while the second is different. Then we run some
 JavaScript to compare the nodes using `isEqualNode()` and output the results.

### HTML

```html
<div>This is the first element.</div>
<div>This is the second element.</div>
<div>This is the first element.</div>

<p id="output"></p>
```

```
#output {
  width: 440px;
  border: 2px solid black;
  border-radius: 5px;
  padding: 10px;
  margin-top: 20px;
  display: block;
}
```

### JavaScript

```js
let output = document.getElementById("output");
let divList = document.getElementsByTagName("div");

output.innerHTML += `div 0 equals div 0: ${divList[0].isEqualNode(
 divList[0],
)}<br/>`;
output.innerHTML += `div 0 equals div 1: ${divList[0].isEqualNode(
 divList[1],
)}<br/>`;
output.innerHTML += `div 0 equals div 2: ${divList[0].isEqualNode(
 divList[2],
)}<br/>`;
```

### Results

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-isequalnode① |

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

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

See also
--------

* `Node.isSameNode()`


Node: getRootNode() method - Web APIs

Node: getRootNode() method
==========================

Baseline Widely available
-------------------------

This feature is well established and works across many devices and browser versions. It’s been available across browsers since January 2020.

* Learn more
* See full compatibility
* Report feedback

 The **`getRootNode()`** method of the `Node` interface
 returns the context object's root,
 which optionally includes the shadow root if it is available.

Syntax
------

```js
getRootNode()
getRootNode(options)
```

### Parameters

`options` Optional

An object that sets options for getting the root node. The available options are:

* `composed`: A boolean value that indicates whether the shadow
 root should be returned (`false`, the default), or a root node beyond
 shadow root (`true`).

### Return value

 An object inheriting from `Node`. This will differ in exact form depending
 on where you call `getRootNode()`; for example:

* Calling it on an element inside a standard web page will return an
 `HTMLDocument` object representing the entire page (or `<iframe>`).
* Calling it on an element inside a shadow DOM will return the associated
 `ShadowRoot`.
* Calling it on an element that is not attached to a document or a shadow tree will return
 the root of the DOM tree it belongs to.
Examples
--------

### Example 1

The first simple example returns a reference to the HTML/document node:

```js
const rootNode = node.getRootNode();
```

### Example 2

 This more complex example shows the difference between returning a normal root, and a
 root including the shadow root:

```html
<div class="parent">
  <div class="child"></div>
</div>
<div class="shadowHost">shadowHost</div>
<pre id="output">Output: </pre>
```

```js
const parent = document.querySelector(".parent");
const child = document.querySelector(".child");
const shadowHost = document.querySelector(".shadowHost");
const output = document.getElementById("output");

output.textContent += `\nparent's root: ${parent.getRootNode().nodeName} \n`; // #document
output.textContent += `child's root: ${child.getRootNode().nodeName} \n\n`; // #document

// create a ShadowRoot
const shadowRoot = shadowHost.attachShadow({ mode: "open" });
shadowRoot.innerHTML =
  '<style>div{background:#2bb8aa;}</style><div class="shadowChild">shadowChild</div>';
const shadowChild = shadowRoot.querySelector(".shadowChild");

// The default value of composed is false
output.textContent += `shadowChild.getRootNode() === shadowRoot : ${
 shadowChild.getRootNode() === shadowRoot
} \n`; // true
output.textContent += `shadowChild.getRootNode({composed:false}) === shadowRoot : ${
 shadowChild.getRootNode({ composed: false }) === shadowRoot
} \n`; // true
output.textContent += `shadowChild.getRootNode({composed:true}).nodeName : ${
 shadowChild.getRootNode({ composed: true }).nodeName
} \n`; // #document
```

### Example 3

 This example returns the root of the unmounted tree.
 Note `element` here is the root of the tree (as it has no parent), so by definition its root is itself:

```js
const element = document.createElement("p");
const child = document.createElement("span");

element.append(child);

const rootNode = child.getRootNode(); // <p><span></span></p>

element === rootNode; // true
element === element.getRootNode(); // true
```

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-getrootnode① |

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

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


Node: contains() method - Web APIs

Node: contains() method
=======================

 The **`contains()`** method of the `Node` interface
 returns a boolean value indicating
 whether a node is a descendant of a given node, that is the node itself,
 one of its direct children (`childNodes`),
 one of the children's direct children, and so on.

**Note:** A node is *contained* inside itself.

Syntax
------

```js
contains(otherNode)
```

### Parameters

`otherNode`

The `Node` to test with.

**Note:** `otherNode` is not optional, but can be set to `null`.

### Return value

 A boolean value that is `true` if `otherNode` is contained in the node,
 `false` if not.

 If the `otherNode` parameter is `null`,
 `contains()` always returns `false`.

Example
-------

 This function checks to see if an element is in the page's body. As
 `contains` is inclusive and determining if the body contains itself isn't the
 intention of `isInPage` this case explicitly returns `false`.

```js
function isInPage(node) {
  return node === document.body ? false : document.body.contains(node);
}
```

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-contains① |

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

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

See also
--------

* `Node.compareDocumentPosition`
* `Node.hasChildNodes`


Node: nextSibling property - Web APIs

Node: nextSibling property
==========================

 The read-only **`nextSibling`** property of the `Node` interface
 returns the node immediately following the specified one in their
 parent's `childNodes`, or returns `null`
 if the specified node is the last child in the parent element.

**Note:** Browsers insert `Text` nodes into a document to represent whitespace in the source markup.
 Therefore a node obtained, for example, using `Node.firstChild`
 or `Node.previousSibling`
 may refer to a whitespace text node rather than the actual element the author
 intended to get.

 The article Whitespace in the DOM
 contains more information about this behavior.

 You can use `Element.nextElementSibling` to obtain the next element
 skipping any whitespace nodes, other between-element text, or comments.

To navigate the opposite way through the child nodes list use Node.previousSibling.

Value
-----

 A `Node` representing the next sibling of the current node,
 or `null` if there are none.

Example
-------

```html
<div id="div-1">Here is div-1</div>
<div id="div-2">Here is div-2</div>
<br />
<output><em>Not calculated.</em></output>
```

```js
let el = document.getElementById("div-1").nextSibling;
let i = 1;

let result = "Siblings of div-1:<br/>";

while (el) {
  result += `${i}. ${el.nodeName}<br/>`;
  el = el.nextSibling;
  i++;
}

const output = document.querySelector("output");
output.innerHTML = result;
```

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-nextsibling① |

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

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

See also
--------

* `Element.nextElementSibling`
* `Node.previousSibling`


Node: appendChild() method - Web APIs

Node: appendChild() method
==========================

The **`appendChild()`** method of the `Node` interface adds a node to the end of the list of children of a specified parent node.

**Note:** If the given child is a reference to an existing node in the document, `appendChild()` moves it from its current position to the new position.

If the given child is a `DocumentFragment`, the entire contents of the `DocumentFragment` are moved into the child list of the specified parent node.

`appendChild()` returns the newly appended node, or if the child is a `DocumentFragment`, the emptied fragment.

**Note:** Unlike this method, the `Element.append()` method supports multiple arguments and appending strings. You can prefer using it if your node is an element.

Syntax
------

```js
appendChild(aChild)
```

### Parameters

`aChild`

The node to append to the given parent node (commonly an element).

### Return value

A `Node` that is the appended child (`aChild`), except when `aChild` is a `DocumentFragment`, in which case the empty `DocumentFragment` is returned.

### Exceptions

`HierarchyRequestError` `DOMException`

Thrown when the constraints of the DOM tree are violated, that is if one of the following cases occurs:

* If the parent of `aChild` is not a `Document`, `DocumentFragment`, or an `Element`.
* If the insertion of `aChild` would lead to a cycle, that is if `aChild` is an ancestor of the node.
* If `aChild` is not a `DocumentFragment`, a `DocumentType`, an `Element`, or a `CharacterData`.
* If the current node is a `Text`, and its parent is a `Document`.
* If the current node is a `DocumentType` and its parent is *not* a `Document`, as a *doctype* should always be a direct descendant of a *document*.
* If the parent of the node is a `Document` and `aChild` is a `DocumentFragment` with more than one `Element` child, or that has a `Text` child.
* If the insertion of `aChild` would lead to `Document` with more than one `Element` as child.

Description
-----------

 If the given child is a reference to an existing node in the document, `appendChild()` moves it from its current position to the new position — there is no requirement to remove the node from its parent
 node before appending it to some other node. This means that a node can't be in two points of the document simultaneously. The `Node.cloneNode()` method can be used to make a copy of the node before appending it under the new parent. Copies made with `cloneNode` are not automatically kept in sync.

`appendChild()` returns the newly appended node, instead of the parent node. This means you can append the new node as soon as it's created without losing reference to it:

```js
const paragraph = document.body.appendChild(document.createElement("p"));
// You can append more elements to the paragraph later
```

On the other hand, you cannot use `appendChild()` in a fluent API fashion (like JQuery).

```js
// This doesn't append three paragraphs:
// the three elements will be nested instead of siblings
document.body
  .appendChild(document.createElement("p"))
  .appendChild(document.createElement("p"))
  .appendChild(document.createElement("p"));
```

Example
-------

### Append a paragraph to the body

```js
// Create a new paragraph element, and append it to the end of the document body
const p = document.createElement("p");
document.body.appendChild(p);
```

### Creating a nested DOM structure

In this example, we attempt to create a nested DOM structure using as few temporary variables as possible.

```js
const fragment = document.createDocumentFragment();
const li = fragment
  .appendChild(document.createElement("section"))
  .appendChild(document.createElement("ul"))
  .appendChild(document.createElement("li"));
li.textContent = "hello world";

document.body.appendChild(fragment);
```

It generates the following DOM tree:

```html
<section>
  <ul>
    <li>hello world</li>
  </ul>
</section>
```

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

| Specification |
| --- |
| DOM Standard # dom-node-appendchild |

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

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

See also
--------

* `Node.removeChild()`
* `Node.replaceChild()`
* `Node.insertBefore()`
* `Node.hasChildNodes()`
* `Element.insertAdjacentElement()`
* `Element.append()`


Node: isConnected property - Web APIs

Node: isConnected property
==========================

Baseline Widely available
-------------------------

This feature is well established and works across many devices and browser versions. It’s been available across browsers since January 2020.

* Learn more
* See full compatibility
* Report feedback

 The read-only **`isConnected`** property of the `Node` interface
 returns a boolean indicating whether the node is connected
 (directly or indirectly) to a `Document` object.

Value
-----

 A boolean value that is `true` if the node is connected to its relevant context object,
 and `false` if not.

Examples
--------

### Standard DOM

A standard DOM example:

```js
let test = document.createElement("p");
console.log(test.isConnected); // Returns false
document.body.appendChild(test);
console.log(test.isConnected); // Returns true
```

### Shadow DOM

A shadow DOM example:

```js
// Create a shadow root
const shadow = this.attachShadow({ mode: "open" });

// Create some CSS to apply to the shadow DOM
const style = document.createElement("style");
console.log(style.isConnected); // returns false

style.textContent = `
.wrapper {
 position: relative;
}

.info {
 font-size: 0.8rem;
 width: 200px;
 display: inline-block;
 border: 1px solid black;
 padding: 10px;
 background: white;
 border-radius: 10px;
 opacity: 0;
 transition: 0.6s all;
 positions: absolute;
 bottom: 20px;
 left: 10px;
 z-index: 3
}
`;

// Attach the created style element to the shadow DOM

shadow.appendChild(style);
console.log(style.isConnected); // Returns true
```

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-isconnected① |

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

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

See also
--------

* Node.prototype.isConnected polyfill


Node: hasChildNodes() method - Web APIs

Node: hasChildNodes() method
============================

 The **`hasChildNodes()`** method of the `Node` interface
 returns a boolean value indicating
 whether the given `Node` has child nodes or not.

Syntax
------

```js
hasChildNodes()
```

### Parameters

None.

### Return value

 A boolean value that is `true` if the node has child nodes, and
 `false` otherwise.

Example
-------

```js
let foo = document.getElementById("foo");

if (foo.hasChildNodes()) {
  // Do something with 'foo.childNodes'
}
```

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-haschildnodes① |

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

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

See also
--------

* `Node.childNodes`


Node: removeChild() method - Web APIs

Node: removeChild() method
==========================

 The **`removeChild()`** method of the `Node` interface
 removes a child node from the DOM and returns the removed node.

**Note:** As long as a reference is kept on the removed child,
 it still exists in memory, but is no longer part of the DOM.
 It can still be reused later in the code.

 If the return value of `removeChild()` is not stored, and no other reference is kept,
 it will be automatically deleted from memory after a short time.

Unlike `Node.cloneNode()` the return value preserves the `EventListener` objects associated with it.

Syntax
------

```js
removeChild(child)
```

### Parameters

`child`

A `Node` that is the child node to be removed from the DOM.

### Exception

`NotFoundError` `DOMException`

Thrown if the `child` is not a child of the node.

`TypeError`

Thrown if the `child` is `null`.

Examples
--------

### Simple examples

Given this HTML:

```html
<div id="parent">
  <div id="child"></div>
</div>
```

To remove a specified element when knowing its parent node:

```js
const parent = document.getElementById("parent");
const child = document.getElementById("child");
const throwawayNode = parent.removeChild(child);
```

To remove a specified element without having to specify its parent node:

```js
const node = document.getElementById("child");
if (node.parentNode) {
  node.parentNode.removeChild(node);
}
```

To remove all children from an element:

```js
const element = document.getElementById("idOfParent");
while (element.firstChild) {
  element.removeChild(element.firstChild);
}
```

### Causing a TypeError

```html
<!--Sample HTML code-->
<div id="parent"></div>
```

```js
const parent = document.getElementById("parent");
const child = document.getElementById("child");

// Throws Uncaught TypeError
const garbage = parent.removeChild(child);
```

### Causing a NotFoundError

```html
<!--Sample HTML code-->
<div id="parent">
  <div id="child"></div>
</div>
```

```js
const parent = document.getElementById("parent");
const child = document.getElementById("child");

// This first call correctly removes the node
const garbage = parent.removeChild(child);

// Throws NotFoundError
garbage = parent.removeChild(child);
```

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

| Specification |
| --- |
| DOM Standard # dom-node-removechild |

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

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

See also
--------

* `Node.replaceChild()`
* `Node.parentNode`
* `Element.remove()`
* `Node.cloneNode()`


Node: normalize() method - Web APIs

Node: normalize() method
========================

 The **`normalize()`** method of the `Node` interface puts the specified node
 and all of its sub-tree into a *normalized* form.
 In a normalized sub-tree, no text nodes in the sub-tree are empty and there are no adjacent text nodes.

Syntax
------

```js
normalize()
```

### Parameters

None.

### Return value

None.

Example
-------

```html
<output id="result"></output>
```

```js
const wrapper = document.createElement("div");

wrapper.appendChild(document.createTextNode("Part 1 "));
wrapper.appendChild(document.createTextNode("Part 2 "));

let node = wrapper.firstChild;
let result = "Before normalization:<br/>";
while (node) {
  result += ` ${node.nodeName}: ${node.nodeValue}<br/>`;
  node = node.nextSibling;
}

wrapper.normalize();

node = wrapper.firstChild;
result += "<br/><br/>After normalization:<br/>";
while (node) {
  result += ` ${node.nodeName}: ${node.nodeValue}<br/>`;
  node = node.nextSibling;
}

const output = document.getElementById("result");
output.innerHTML = result;
```

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-normalize① |

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

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

See also
--------

* `Text.splitText()`, its opposite.


Node: compareDocumentPosition() method - Web APIs

Node: compareDocumentPosition() method
======================================

 The **`compareDocumentPosition()`** method of the `Node` interface
 reports the position of its argument node relative to the node on which it is called.

Syntax
------

```js
compareDocumentPosition(otherNode)
```

### Parameters

`otherNode`

The `Node` for which position should be reported, relative to the node.

### Return value

 An integer value representing `otherNode`'s position relative to `node`
 as a bitmask combining the
 following constant properties of `Node`:

`Node.DOCUMENT_POSITION_DISCONNECTED` (`1`)

Both nodes are in different documents or different trees in the same document.

`Node.DOCUMENT_POSITION_PRECEDING` (`2`)

`otherNode` precedes the node in either a pre-order depth-first traversal of a tree containing both (e.g., as an ancestor or previous sibling or a descendant of a previous sibling or previous sibling of an ancestor) or (if they are disconnected) in an arbitrary but consistent ordering.

`Node.DOCUMENT_POSITION_FOLLOWING` (`4`)

`otherNode` follows the node in either a pre-order depth-first traversal of a tree containing both (e.g., as a descendant or following sibling or a descendant of a following sibling or following sibling of an ancestor) or (if they are disconnected) in an arbitrary but consistent ordering.

`Node.DOCUMENT_POSITION_CONTAINS` (`8`)

`otherNode` is an ancestor of the node.

`Node.DOCUMENT_POSITION_CONTAINED_BY` (`16`)

`otherNode` is a descendant of the node.

`Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC` (`32`)

The result relies upon arbitrary and/or implementation-specific behavior and is not guaranteed to be portable.

 More than one bit is set if multiple scenarios apply. For example, if
 `otherNode` is located earlier in the document ***and***
 contains the node on which `compareDocumentPosition()` was
 called, then both the `DOCUMENT_POSITION_CONTAINS` and
 `DOCUMENT_POSITION_PRECEDING` bits would be set, producing a value of `10` (`0x0A`).

Example
-------

```js
const head = document.head;
const body = document.body;

if (head.compareDocumentPosition(body) & Node.DOCUMENT\_POSITION\_FOLLOWING) {
  console.log("Well-formed document");
} else {
  console.error("<head> is not before <body>");
}
```

**Note:** Because the result returned by `compareDocumentPosition()` is a bitmask,
 the bitwise AND operator
 must be used for meaningful results.

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-comparedocumentposition① |

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

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

See also
--------

* `Node.contains()`


Node: ownerDocument property - Web APIs

Node: ownerDocument property
============================

 The read-only **`ownerDocument`** property of the `Node` interface
 returns the top-level document object of the node.

Value
-----

 A `Document` that is the top-level object in which all the
 child nodes are created.

If this property is used on a node that is itself a document, the value is `null`.

Example
-------

```js
// Given a node "p", get the top-level HTML
// child of the document object

const d = p.ownerDocument;
const html = d.documentElement;
```

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-ownerdocument① |

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

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


Node: cloneNode() method - Web APIs

Node: cloneNode() method
========================

 The **`cloneNode()`** method of the `Node` interface
 returns a duplicate of the node on which this method was called.
 Its parameter controls if the subtree contained in a node is also cloned or not.

 Cloning a node copies all of its attributes and their values,
 including intrinsic (inline) listeners. It does *not* copy event listeners added
 using `addEventListener()` or
 those assigned to element properties (e.g., `node.onclick = someFunction`).
 Additionally, for a `<canvas>` element, the painted image is not copied.

**Warning:** `cloneNode()` may lead to duplicate element IDs in a document!

 If the original node has an `id` attribute, and the clone
 will be placed in the same document, then you should modify the clone's ID to be
 unique.

 Also, `name` attributes may need to be modified,
 depending on whether duplicate names are expected.

 To clone a node to insert into a *different* document, use
 `Document.importNode()` instead.

Syntax
------

```js
cloneNode()
cloneNode(deep)
```

### Parameters

`deep` Optional

 If `true`, then the node and its whole subtree,
 including text that may be in child `Text` nodes,
 is also copied.

 If `false`, only the node will be cloned.
 The subtree, including any text that the node contains, is not cloned.

 Note that `deep` has no effect on void elements,
 such as the `<img>` and `<input>` elements.

### Return value

 The new `Node` cloned.
 The cloned node has no parent and is not part of the document,
 *until* it is added to another node that is part of the document,
 using `Node.appendChild()` or a similar method.

Example
-------

```js
let p = document.getElementById("para1");
let p_prime = p.cloneNode(true);
```

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

| Specification |
| --- |
| DOM Standard # ref-for-dom-node-clonenode① |

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

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