react: Bug: Reconciler cannot handle Declarative Shadow DOM (DSD)
The reconciler does not ignore <template shadowRoot="open"> but handles them like a normal HostElement.
In reality, as soon as the closing template tag is parsed, the component is replaced in the DOM by #shadow-root (open)
See: https://github.com/mfreed7/declarative-shadow-dom#-behavior
React version: 18.2.0
Steps To Reproduce
I tried this with NextJS 13.1.6, which uses react 18.2.0 and react-dom 18.2.0.
In the end the component is rendered server side and hydrated in the frontend.
- Add the following html code to your component
<div>
<template shadowrootmode="open">
<button type="button">
<slot></slot>
</button>
</template>
My button
</div>
- Render the component via SSR and hydrate in the frontend.
The current behavior
A hydration warning is thrown:
Expected server HTML to contain a matching <template> in <div>.
at template
at div
at Home
The expected behavior
In the end i guess a DSD should be handled as an isolation block where on the server the DSD template tag is allowed, but on the client hydration all children of the block are hydrated to the now existing ShadowRoot.
Server -> Render template tag Client -> Children of template tag are hydrated against the ShadowRoot fragment.
About this issue
- Original URL
- State: open
- Created a year ago
- Reactions: 15
- Comments: 15
Note that it’s now
shadowrootmodeand notshadowroot.I tried this in the latest version of both Remix and Next.js. It’s definitely an issue.
@jonathandewitt-dev
I’m currently working on updating my NextJS/WebComponent Repo by getting a StencilJS component working
Once this is done i will have a look on what needs to be adjusted in react-dom so i do not have to handle server and client differently because of the shadowRoot template tag, as seen here.
It is about the core concept.
Server -> Render tag, DSD and component nodes Client -> Hydrate component nodes using existing ShadowRoot.
There is no reason the handle DSD on the client at all. At least not the tag, but React must replace it on client hydration with the ShadowRoot as the hydration root.
It is also not correct as i wrote in my initial post here that
React should ignore the <template shadowroot="open"> tag and all its childrenCases like having an onClick here should of course still work:
The isolation of WebComponents and hydrating only specific ShadowRoots helps here. Meaning you can render something for a component on the server (tag, dsd, content) and use a different render/hydration target and just the component content on the client.
The only solution i could think of would be that React handles DSD
<template>tags as an isolation block, meaning on hydration it searches for an ShadowRoot fragment in place of the DSD and hydrates all the children to that ShadowRoot.