Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v22
v24
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,7 @@ To begin with, let's put together a basic function.
closeBtn.textContent = "x";
panel.appendChild(closeBtn);

closeBtn.addEventListener("click", () =>
panel.parentNode.removeChild(panel),
);
closeBtn.addEventListener("click", () => body.removeChild(panel));
```

This is quite a lot of code to go through, so we'll walk you through it bit by bit.
Expand Down Expand Up @@ -117,10 +115,10 @@ panel.appendChild(closeBtn);

Finally, we call {{domxref("EventTarget/addEventListener", "addEventListener()")}} to add a function that will be called when the user clicks the "close" button. The code will delete the whole panel from the page — to close the message box.

Briefly, the `addEventListener()` method is provided by the button (or in fact, any element on the page) that can be passed a function and the name of an event. In this case, the name of the event is 'click', meaning that when the user clicks the button, the function will run. You'll learn a lot more about events in our [events article](/en-US/docs/Learn_web_development/Core/Scripting/Events). The line inside the function uses the {{domxref("Node.removeChild()")}} DOM API function to specify that we want to remove a specific child element of the HTML element in this case, the panel `<div>`.
Briefly, the `addEventListener()` method can be called on any element on the page, and is usually passed two arguments: the name of an event and a function to run when the event occurs. In this case, the event name is `click`, meaning that when the user clicks the button, the function will run. You'll learn a lot more about events in our [events article](/en-US/docs/Learn_web_development/Core/Scripting/Events). The line inside the function uses the {{domxref("Node.removeChild()", "removeChild()")}} method to specify that we want to remove a specific child element of the `<body>` element: in this case, the panel `<div>`.

```js
closeBtn.addEventListener("click", () => panel.parentNode.removeChild(panel));
closeBtn.addEventListener("click", () => body.removeChild(panel));
```

Basically, this whole block of code is generating a block of HTML that looks like so, and inserting it into the page:
Expand Down
1 change: 1 addition & 0 deletions files/en-us/mozilla/firefox/releases/144/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Firefox 144 was released on [October 14, 2025](https://whattrainisitnow.com/rele
- The [View Transition API](/en-US/docs/Web/API/View_Transition_API) is now supported for [SPAs (single-page applications)](/en-US/docs/Glossary/SPA). This provides a mechanism for easily creating animated transitions between different website views. ([Firefox bug 1985809](https://bugzil.la/1985809)).
- The {{domxref("CSSStyleProperties")}} interface of the [CSS Object Model (CSSOM)](/en-US/docs/Web/API/CSS_Object_Model) is now implemented (this was renamed from a non-standard interface `CSS2Properties`). The new interface is present but not yet used. ([Firefox bug 1919582](https://bugzil.la/1919582)).
- The {{domxref("PerformanceEventTiming.interactionId", "interactionId")}} property of the {{domxref("PerformanceEventTiming")}} interface is a unique identifier that associates related events belonging to a single user interaction. This can be used to calculate the {{glossary("Interaction to next paint")}} metric, which helps analyze responsiveness to user interaction over the lifetime of a page. ([Firefox bug 1956809](https://bugzil.la/1956809)).
- The {{domxref("Navigation.navigate()")}} method of the {{domxref("Navigation API", "Navigation API", "", "nocode")}} no longer accepts URLs with a scheme of `javascript`. Calling `navigate()` with a `javascript:` URL now throws a `NotSupportedError` exception. ([Firefox bug 1981104](https://bugzil.la/1981104)).

#### DOM

Expand Down
6 changes: 3 additions & 3 deletions files/en-us/web/api/customelementregistry/get/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@ customElements.define(
"my-paragraph",
class extends HTMLElement {
constructor() {
let templateContent = document.getElementById("custom-paragraph").content;
const template = document.getElementById("custom-paragraph");
super() // returns element this scope
.attachShadow({ mode: "open" }) // sets AND returns this.shadowRoot
.append(templateContent.cloneNode(true));
.append(document.importNode(template.content, true));
}
},
);

// Return a reference to the my-paragraph constructor
let ctor = customElements.get("my-paragraph");
const ctor = customElements.get("my-paragraph");
```

## Specifications
Expand Down
4 changes: 2 additions & 2 deletions files/en-us/web/api/customelementregistry/getname/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ The name for the previously defined custom element, or `null` if there is no cus
```js
class MyParagraph extends HTMLElement {
constructor() {
let templateContent = document.getElementById("custom-paragraph").content;
const template = document.getElementById("custom-paragraph");
super() // returns element this scope
.attachShadow({ mode: "open" }) // sets AND returns this.shadowRoot
.append(templateContent.cloneNode(true));
.append(document.importNode(template.content, true));
}
}

Expand Down
16 changes: 7 additions & 9 deletions files/en-us/web/api/document/importnode/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,13 @@ browser-compat: api.Document.importNode

{{APIRef("DOM")}}

The {{domxref("Document")}} object's **`importNode()`** method creates a copy of a
{{domxref("Node")}} or {{domxref("DocumentFragment")}} from another document, to be
inserted into the current document later.
The **`importNode()`** method of the {{domxref("Document")}} interface creates a copy of a {{domxref("Node")}} or {{domxref("DocumentFragment")}} from another document, to be inserted into the current document later.

The imported node is not yet included in the document tree. To include it, you need to
call an insertion method such as {{domxref("Node.appendChild", "appendChild()")}} or
{{domxref("Node.insertBefore", "insertBefore()")}} with a node that _is_
currently in the document tree.
The imported node is not yet included in the document tree. To include it, you need to call an insertion method such as {{domxref("Node.appendChild", "appendChild()")}} or {{domxref("Node.insertBefore", "insertBefore()")}} with a node that _is_ currently in the document tree.

Unlike {{domxref("document.adoptNode()")}}, the original node is not removed from its
original document. The imported node is a clone of the original.
Unlike {{domxref("document.adoptNode()")}}, the original node is not removed from its original document. The imported node is a clone of the original.

The {{domxref("Node.cloneNode()")}} method also creates a copy of a node. The difference is that `importNode()` clones the node in the context of the calling document, whereas `cloneNode()` uses the document of the node being cloned. The document context determines the {{domxref("CustomElementRegistry")}} for constructing any custom elements. For this reason, to clone nodes to be used in another document, use `importNode()` on the target document. The {{domxref("HTMLTemplateElement.content")}} is owned by a separate document, so it should also be cloned using `document.importNode()` so that custom element descendants are constructed using the definitions in the current document. See the {{domxref("Node.cloneNode()")}} page's examples for more details.

## Syntax

Expand Down Expand Up @@ -50,6 +46,8 @@ The copied `importedNode` in the scope of the importing document.

## Examples

### Using importNode()

```js
const iframe = document.querySelector("iframe");
const oldNode = iframe.contentWindow.document.getElementById("myNode");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ function displayStatus() {
while (fragmentViewer.hasChildNodes()) {
fragmentViewer.removeChild(fragmentViewer.lastChild);
}
for (entry of fragment.children) {
for (const entry of fragment.children) {
fragmentViewer.appendChild(entry.cloneNode(true));
}
}
Expand Down
30 changes: 26 additions & 4 deletions files/en-us/web/api/htmltemplateelement/content/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,41 @@ browser-compat: api.HTMLTemplateElement.content

{{APIRef("Web Components")}}

The **`HTMLTemplateElement.content`** property returns a
`<template>` element's template contents (a
{{domxref("DocumentFragment")}}).
The **`content`** property of the {{domxref("HTMLTemplateElement")}} interface returns the `<template>` element's template contents as a {{domxref("DocumentFragment")}}. This content's {{domxref("Node/ownerDocument", "ownerDocument")}} is a separate {{domxref("Document")}} from the one that contains the `<template>` element itself — unless the containing document is itself constructed for the purpose of holding template content.

The {{domxref("Node.cloneNode()")}} and {{domxref("Document.importNode()")}} methods both create a copy of a node. The difference is that `importNode()` clones the node in the context of the calling document, whereas `cloneNode()` uses the document of the node being cloned. The document context determines the {{domxref("CustomElementRegistry")}} for constructing any custom elements. For this reason, use `document.importNode()` to clone the `content` fragment so that custom element descendants are constructed using the definitions in the current document, rather than the separate document that owns the template content. See the {{domxref("Node.cloneNode()")}} page's examples for more details.

## Value

A {{domxref("DocumentFragment")}}.

## Examples

### Using importNode() with template content

```js
const templateElement = document.querySelector("#foo");
const documentFragment = templateElement.content.cloneNode(true);
const documentFragment = document.importNode(templateElement.content, true);
// Now you can insert the documentFragment into the DOM
```

### The ownerDocument of template content

For `<template>` elements created in the context of a normal HTML document, the `ownerDocument` of the `content` is a separate, freshly created document:

```js
const template = document.createElement("template");
console.log(template.content.ownerDocument === document); // false
console.log(template.content.ownerDocument.URL); // "about:blank"
```

If the `<template>` element is created in the context of a document that itself was created for the purpose of holding template content, then the `ownerDocument` of the `content` is the same as that of the containing document:

```js
const template1 = document.createElement("template");
const docForTemplate = template1.content.ownerDocument;
const template2 = docForTemplate.createElement("template");
console.log(template2.content.ownerDocument === docForTemplate); // true
```

## Specifications
Expand Down
17 changes: 8 additions & 9 deletions files/en-us/web/api/intersection_observer_api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -600,11 +600,12 @@ To get a feeling for how thresholds work, try scrolling the box below around. Ea
let observers = [];

startup = () => {
let wrapper = document.querySelector(".wrapper");
const wrapper = document.querySelector(".wrapper");
const template = document.querySelector("#boxTemplate");

// Options for the observers

let observerOptions = {
const observerOptions = {
root: null,
rootMargin: "0px",
threshold: [],
Expand All @@ -615,7 +616,7 @@ startup = () => {
// since there will be so many of them (for each percentage
// point).

let thresholdSets = [
const thresholdSets = [
[],
[0.5],
[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0],
Expand All @@ -629,12 +630,10 @@ startup = () => {
// Add each box, creating a new observer for each

for (let i = 0; i < 4; i++) {
let template = document
.querySelector("#boxTemplate")
.content.cloneNode(true);
let boxID = `box${i + 1}`;
template.querySelector(".sampleBox").id = boxID;
wrapper.appendChild(document.importNode(template, true));
const newBox = document.importNode(template.content, true);
const boxID = `box${i + 1}`;
newBox.querySelector(".sampleBox").id = boxID;
wrapper.appendChild(newBox);

// Set up the observer for this box

Expand Down
10 changes: 6 additions & 4 deletions files/en-us/web/api/navigation/navigate/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ navigate(url, options)
### Parameters

- `url`
- : The destination URL to navigate to. Note that when calling `navigate()` on another window's `navigation` object, the URL will be resolved relative to the target window's URL, not the calling window's URL. This matches the behavior of the [History API](/en-US/docs/Web/API/History_API), but not the behavior of the [Location API](/en-US/docs/Web/API/Location).
- : The destination URL to navigate to. Note that when calling `navigate()` on another window's `navigation` object, the URL will be resolved relative to the target window's URL, not the calling window's URL. This matches the behavior of the [History API](/en-US/docs/Web/API/History_API), but not the behavior of the [Location API](/en-US/docs/Web/API/Location). Note also that `javascript:` URLs are not allowed for security reasons.
- `options` {{optional_inline}}
- : An options object containing the following properties:
- `state` {{optional_inline}}
Expand All @@ -50,12 +50,14 @@ Either one of these promises rejects if the navigation has failed for some reaso
### Exceptions

- `DataCloneError` {{domxref("DOMException")}}
- : Thrown if the `state` parameter had values included in it that are not structured-cloneable.
- : Thrown if the `state` parameter contains values that are not structured-cloneable.
- `InvalidStateError` {{domxref("DOMException")}}
- : Thrown if the document is not currently active.
- `SyntaxError` {{domxref("DOMException")}}
- : Thrown if the `url` parameter is not a valid URL.
- `NotSupportedError` {{domxref("DOMException")}}
- : Thrown if the `history` option is set to `push`, and any of the following special circumstances are true:
- The browser is currently showing the initial `about:blank` document.
- : Thrown if:
- The `history` option is set to `push`, and the browser is currently showing the initial `about:blank` document.
- The `url`'s scheme is `javascript`.

## Examples
Expand Down
58 changes: 40 additions & 18 deletions files/en-us/web/api/node/clonenode/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,16 @@ browser-compat: api.Node.cloneNode

{{APIRef("DOM")}}

The **`cloneNode()`** method of the {{domxref("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.
The **`cloneNode()`** method of the {{domxref("Node")}} interface returns a duplicate of the node on which this method was called. Its parameter controls if the subtree contained in the 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()`](/en-US/docs/Web/API/EventTarget/addEventListener) or
those assigned to element properties (e.g., `node.onclick = someFunction`).
Additionally, for a {{HTMLElement("canvas")}} element, the painted image is not copied.
By default, cloning a node copies all of its attributes and their values, including event listeners specified via attributes. By setting the `deep` parameter, you can also copy the subtree contained in the node. It does _not_ copy any other internal data, such as event listeners added using [`addEventListener()`](/en-US/docs/Web/API/EventTarget/addEventListener) or `onevent` properties (e.g., `node.onclick = someFunction`), or the painted image for a {{HTMLElement("canvas")}} element.

The {{domxref("Document.importNode()")}} method also creates a copy of a node. The difference is that `importNode()` clones the node in the context of the calling document, whereas `cloneNode()` uses the document of the node being cloned. The document context determines the {{domxref("CustomElementRegistry")}} for constructing any custom elements. For this reason, to clone nodes to be used in another document, use `importNode()` on the target document. The {{domxref("HTMLTemplateElement.content")}} is owned by a separate document, so it should also be cloned using `document.importNode()` so that custom element descendants are constructed using the definitions in the current document.

> [!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.
> `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
{{domxref("Document.importNode()")}} instead.
> Also, `name` attributes may need to be modified, depending on whether duplicate names are expected.

## Syntax

Expand Down Expand Up @@ -60,11 +48,45 @@ using {{domxref("Node.appendChild()")}} or a similar method.

## Example

### Using cloneNode()

```js
const p = document.getElementById("para1");
const p2 = p.cloneNode(true);
```

### Using cloneNode() with templates

Avoid using `cloneNode()` on the content of a {{htmlelement("template")}} element, because if the template contains custom elements, they will not be upgraded until they are inserted into the document.

```js
class MyElement extends HTMLElement {
constructor() {
super();
console.log("MyElement created");
}
}
customElements.define("my-element", MyElement);

const template = document.createElement("template");
template.innerHTML = `<my-element></my-element>`;

const clone = template.content.cloneNode(true);
// No log here; my-element is undefined in the template's document
customElements.upgrade(clone);
// Still no log; my-element is still undefined in the template's document
document.body.appendChild(clone);
// Logs "MyElement created"; my-element is now upgraded
```

Instead, use `document.importNode()` to clone the template content, so that any custom elements are upgraded using the definitions in the current document:

```js
const clone = document.importNode(template.content, true);
// Logs "MyElement created"; my-element is upgraded using document's definitions
document.body.appendChild(clone);
```

## Specifications

{{Specifications}}
Expand Down
7 changes: 2 additions & 5 deletions files/en-us/web/api/shadowroot/elementfrompoint/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,9 @@ customElements.define(
class extends HTMLElement {
constructor() {
super();
const templateContent = document.getElementById(
"my-custom-element-template",
).content;
const template = document.getElementById("my-custom-element-template");
const sRoot = this.attachShadow({ mode: "open" });
sRoot.appendChild(templateContent.cloneNode(true));

sRoot.appendChild(document.importNode(template.content, true));
// get the topmost element in the top left corner of the viewport
const srElement = this.shadowRoot.elementFromPoint(0, 0);
// apply a border to that element
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ customElements.define(
let templateContent = template.content;

const shadowRoot = this.attachShadow({ mode: "open" });
shadowRoot.appendChild(templateContent.cloneNode(true));
shadowRoot.appendChild(document.importNode(templateContent, true));
}
},
);
```

The key point to note here is that we append a clone of the template content to the shadow root, created using the {{domxref("Node.cloneNode()")}} method.
The key point to note here is that we append a clone of the template content to the shadow root, created using the {{domxref("Document.importNode()")}} method.

And because we are appending its contents to a shadow DOM, we can include some styling information inside the template in a {{htmlelement("style")}} element, which is then encapsulated inside the custom element.
This wouldn't work if we just appended it to the standard DOM.
Expand Down Expand Up @@ -255,7 +255,7 @@ customElements.define(
"element-details-template",
).content;
const shadowRoot = this.attachShadow({ mode: "open" });
shadowRoot.appendChild(template.cloneNode(true));
shadowRoot.appendChild(document.importNode(template, true));
}
},
);
Expand Down
Loading