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

There have been a few changes to declarative shadow DOM #32289

Closed
mfreed7 opened this issue Feb 15, 2024 · 8 comments · Fixed by #33650
Closed

There have been a few changes to declarative shadow DOM #32289

mfreed7 opened this issue Feb 15, 2024 · 8 comments · Fixed by #33650
Assignees
Labels
Content:WebAPI Web API docs

Comments

@mfreed7
Copy link

mfreed7 commented Feb 15, 2024

MDN URL

https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow

What specific section or headline is this issue about?

Declarative shadow DOM

What information was incorrect, unhelpful, or incomplete?

There have been some recent spec changes to declarative shadow DOM:

Thanks!

What did you expect to see?

See above.

Do you have any supporting links, references, or citations?

No response

Do you have anything more you want to share?

No response

@mfreed7 mfreed7 added the needs triage Triage needed by staff and/or partners. Automatically applied when an issue is opened. label Feb 15, 2024
@github-actions github-actions bot added the Content:WebAPI Web API docs label Feb 15, 2024
@bsmth
Copy link
Member

bsmth commented Feb 23, 2024

Thanks a lot for reporting. Tagging @pepelsbey who has better context on these docs lately

@pepelsbey
Copy link
Member

pepelsbey commented Apr 4, 2024

@pepelsbey pepelsbey removed the needs triage Triage needed by staff and/or partners. Automatically applied when an issue is opened. label Apr 4, 2024
@pepelsbey
Copy link
Member

Are you sure that shadowrootclonable should be a part of HTMLTemplateElement interface? The <template> element, when used for declarative shadow DOM, disappears from the DOM during the parsing and gets replaced by the shadow root.

  • Calling attachShadow() with an existing declarative shadow root worked previously but will now throw an exception if the mode doesn't match the existing root's mode. I don't believe this is documented anywhere, but this page says an InvalidStateException will be thrown if there's already a shadow root, which isn't exactly true.

I can only confirm this behavior in Chrome:

Uncaught DOMException: Failed to execute 'attachShadow' on 'Element': The requested mode does not match the existing declarative shadow root's mode

Both Firefox and Safari don’t throw any exceptions when I try to attach a shadow with a mode different from the one that is declared via the shadowrootmode attribute:

<p>outer</p>
<div>
    <template shadowrootmode="open">
        <p>inner</p>
    </template>
</div>
<script>
    const div = document.querySelector('div');
    const shadow = div.attachShadow({ mode: 'closed' });
    const span = document.createElement('span');

    span.textContent = 'text';
    shadow.appendChild(span);
</script>

@mfreed7
Copy link
Author

mfreed7 commented Apr 5, 2024

Are you sure that shadowrootclonable should be a part of HTMLTemplateElement interface? The <template> element, when used for declarative shadow DOM, disappears from the DOM during the parsing and gets replaced by the shadow root.

Yes, it's a bit odd, since in the normal course of usage you'd never do myTemplate.shadowRootClonable=true. There is some spec discussion about this still. But as-is the spec says all of the shadowroot* attributes get reflected to HTMLTemplateElement. That's shadowRootMode, shadowRootClonable, shadowRootSerializable, and shadowRootDelegatesFocus. As of Chrome 125 all of these should be supported.

I can only confirm this behavior in Chrome:

Uncaught DOMException: Failed to execute 'attachShadow' on 'Element': The requested mode does not match the existing declarative shadow root's mode

Both Firefox and Safari don’t throw any exceptions when I try to attach a shadow with a mode different from the one that is declared via the shadowrootmode attribute:

Right, I don't think they've shipped the new behavior yet. I shipped it in Chrome v122, pretty recently. I'm hoping/guessing Gecko and WebKit aren't far behind.

@hamishwillee
Copy link
Collaborator

@pepelsbey FYI, the first two points have been addressed this week in MDN as part of the FF releases.

As stated above the [HTMLTemplateElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTemplateElement) think is a spec oddity in that once you've parsed the <template> if it defines a declarative shadow root the whole object does not exist because it is replaced by the ShadowRoot. Conversely if the <template> is not a shadow root then it will create a HTMLTemplateElement but the shadow properties are meaningless, because it is not a shadow root and cannot subsequently be turned into a shadow root.

I have said that so that it is clear the properties are pointless.

@hamishwillee
Copy link
Collaborator

hamishwillee commented May 14, 2024

@pepelsbey @mfreed7 As per the note above, only the last point remains

  • Calling attachShadow() with an existing declarative shadow root worked previously, but will now throw an exception if the mode doesn't match the existing root's mode. I don't believe this is documented anywhere, but this page says an InvalidStateException will be thrown if there's already a shadow root, which isn't exactly true.

@mfreed7 you noted that in attachShadow() there is the exception:

InvalidStateError

  • DOMException
    The element you are trying to attach to is already a shadow host.

Looking round I find whatwg/dom#1235 (comment)

So would I be correct that the spec has been updated as stated?:

  • If two declarative shadow roots are included within a single host element, only the first one will remain. This is a change in behavior from before, but it hopefully won't encounter compat issues
  • If attachShadow() is used on an existing declarative shadow root, and the parameters (e.g. shadow root type, delegates focus, etc.) do not match, an exception is thrown. This, also, is a breaking change, but again hopefully not one that has compat implications.
  • If attachShadow() is used on an existing declarative shadow root, and the parameters do match then I recall discussion that state that the declaratively declared shadow root is cleared and returned. But what is the implication of this? I.e. in particular for a web component, I imagine the web component created a shadow tree with CSS and Javascript inside the original template tage - so this all gets deleted? How is the component supposed to recreate this stuff when attachShadow is called. I'm aware this might be a dumb question :-0

FYI, I'm doing this for #32731 - might end up having more questions there.

@mfreed7
Copy link
Author

mfreed7 commented May 14, 2024

  • If two declarative shadow roots are included within a single host element, only the first one will remain. This is a change in behavior from before, but it hopefully won't encounter compat issues

That's correct. It's a change, but it's been shipped in Chrome and we haven't seen issues. This is fairly corner case - most people don't include more than one declarative shadow root <template>.

  • If attachShadow() is used on an existing declarative shadow root, and the parameters (e.g. shadow root type, delegates focus, etc.) do not match, an exception is thrown. This, also, is a breaking change, but again hopefully not one that has compat implications.

Right. If the parameters don't match, an exception will be thrown now. Again, shipped in Chrome and we haven't seen compat issues.

  • If attachShadow() is used on an existing declarative shadow root, and the parameters do match then I recall discussion that state that the declaratively declared shadow root is cleared and returned. But what is the implication of this? I.e. in particular for a web component, I imagine the web component created a shadow tree with CSS and Javascript inside the original template tage - so this all gets deleted? How is the component supposed to recreate this stuff when attachShadow is called. I'm aware this might be a dumb question :-0

That's also right. The point of this behavior is for web components that are implemented without knowledge of declarative shadow roots that might be present due to server side rendering, for example. To avoid breaking those components, if they call attachShadow() and there's an existing shadow root, it gets cleared and returned so that the web component code can populate that shadow root as it expects to do, without exceptions.

@hamishwillee
Copy link
Collaborator

Thanks @mfreed7 - I have captured this in #33650 - would appreciate your sanity check of that.

Note that according to the spec you can attachShadow() on a declaratively created shadow host with matching mode - the other properties such as delegatesFocus, serializable overright the original declarative settings. So that is what I have documented. Otherwise calling attachShadow() throws.

Anyway, once that goes in, this issue can close.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Content:WebAPI Web API docs
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants