Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only one shadow root can be attached to an element #33650

Merged
merged 1 commit into from
May 17, 2024
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
19 changes: 15 additions & 4 deletions files/en-us/web/api/element/attachshadow/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ The following is a list of elements you _can_ attach a shadow root to:
- {{htmlelement("section")}}
- {{htmlelement("span")}}

## Calling this method on an element that is already a shadow host

The method may be called on an element that already has a [declarative shadow root](/en-US/docs/Web/HTML/Element/template#declarative_shadow_dom), provided the specified mode `mode` matches the existing mode.
In this case the {{domxref("ShadowRoot")}} that was already present will be cleared and returned.
This allows for cases where, for example, server-side rendering has already declaratively created a shadow root, and then client-side code attempts to attach the root again.

Otherwise calling `attachShadow()` on an element that already has a shadow root will throw an exception.

## Syntax

```js-nolint
Expand Down Expand Up @@ -99,11 +107,14 @@ Returns a {{domxref("ShadowRoot")}} object.

### Exceptions

- `InvalidStateError` {{domxref("DOMException")}}
- : The element you are trying to attach to is already a shadow host.
- `NotSupportedError` {{domxref("DOMException")}}
- : You are trying to attach a shadow root to an element outside the HTML namespace, the element cannot have a shadow attached to it,
or the static property `disabledFeatures` has been given a value of `"shadow"` in the element definition.

- : This may can be thrown when you try to attach a shadow root to an element:

- outside the HTML namespace or that can't have a shadow attached to it.
- where the element definition static property `disabledFeatures` has been given a value of `"shadow"` .
- that already has a shadow root that was not created declaratively.
- that has a [declarative shadow root](/en-US/docs/Web/HTML/Element/template#declarative_shadow_dom) but the specified `mode` does not match the existing mode.

## Examples

Expand Down
17 changes: 11 additions & 6 deletions files/en-us/web/html/element/template/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ This element includes the [global attributes](/en-US/docs/Web/HTML/Global_attrib

- : Hides the internal shadow root DOM from JavaScript.

> **Note:** If this attribute is set, the HTML parser creates a {{domxref("ShadowRoot")}} object in the DOM.
> If the attribute is not set, or not set to an allowed value, then a {{domxref("HTMLTemplateElement")}} is constructed.
> **Note:** The HTML parser creates a {{domxref("ShadowRoot")}} object in the DOM for the first `<template>` in a node with this attribute set to an allowed value.
> If the attribute is not set, or not set to an allowed value — or if a `ShadowRoot` has already been declaratively created in the same parent — then an {{domxref("HTMLTemplateElement")}} is constructed.
> A {{domxref("HTMLTemplateElement")}} cannot subsequently be changed into a shadow root after parsing, for example, by setting {{domxref("HTMLTemplateElement.shadowRootMode")}}.

> **Note:** You may find the non-standard `shadowroot` attribute in older tutorials and examples that used to be supported in Chrome 90-110. This attribute has since been removed and replaced by the standard `shadowrootmode` attribute.
Expand All @@ -50,15 +50,20 @@ There are two main ways to use the `<template>` element.

### Template document fragment

By default, the element's content is not rendered, but is parsed into a [document fragment](/en-US/docs/Web/API/DocumentFragment).
Using the {{domxref("HTMLTemplateElement.content", "content")}} property in JavaScript, this fragment can be cloned via the {{domxref("Node.cloneNode", "cloneNode")}} method and inserted into the DOM.
By default, the element's content is not rendered.
The corresponding {{domxref("HTMLTemplateElement")}} interface includes a standard {{domxref("HTMLTemplateElement.content", "content")}} property (without an equivalent content/markup attribute). This `content` property is read-only and holds a {{domxref("DocumentFragment")}} that contains the DOM subtree represented by the template.
This fragment can be cloned via the {{domxref("Node.cloneNode", "cloneNode")}} method and inserted into the DOM.

Be careful when using the `content` property because the returned `DocumentFragment` can exhibit unexpected behavior.
For more details, see the [Avoiding DocumentFragment pitfalls](#avoiding_documentfragment_pitfalls) section below.

### Declarative Shadow DOM

If the element contains the [`shadowrootmode`](#shadowrootmode) attribute, the HTML parser will immediately generate a shadow DOM. The element is replaced in the DOM by its content wrapped in a [shadow root](/en-US/docs/Glossary/Shadow_tree), which is attached to the parent element.
If the `<template>` element contains the [`shadowrootmode`](#shadowrootmode) attribute with a value of either `open` or `closed`, the HTML parser will immediately generate a shadow DOM. The element is replaced in the DOM by its content wrapped in a {{domxref("ShadowRoot")}}, which is attached to the parent element.
This is the declarative equivalent of calling {{domxref("Element.attachShadow()")}} to attach a shadow root to an element.

The corresponding {{domxref("HTMLTemplateElement")}} interface includes a standard {{domxref("HTMLTemplateElement.content", "content")}} property (without an equivalent content/markup attribute). This `content` property is read-only and holds a {{domxref("DocumentFragment")}} that contains the DOM subtree represented by the template. Be careful when using the `content` property because the returned `DocumentFragment` can exhibit unexpected behavior. For more details, see the [Avoiding DocumentFragment pitfalls](#avoiding_documentfragment_pitfalls) section below.
If the element has any other value for `shadowrootmode`, or does not have the `shadowrootmode` attribute, the parser generates a {{domxref("HTMLTemplateElement")}}.
Similarly, if there are multiple declarative shadow roots, only the first one is replaced by a {{domxref("ShadowRoot")}} — subsequent instances are parsed as {{domxref("HTMLTemplateElement")}} objects.

## Examples

Expand Down