Skip to content

Commit

Permalink
Only one shadow root can be attached to an element (#33650)
Browse files Browse the repository at this point in the history
  • Loading branch information
hamishwillee authored May 17, 2024
1 parent a67dbdb commit 4f7f3f7
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 10 deletions.
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

0 comments on commit 4f7f3f7

Please sign in to comment.