Skip to content

Hydration with shadow root doesn't work #52

@amthrock

Description

@amthrock

If you register a component as a custom element with { shadow: true } then the code in the connectedCallback will try to run the hydrate function with the shadow root as the target node. This ends up rendering the entire component inside the shadow root while preserving, but not rendering, existing children (perhaps they're being treated like slot contents?) outside the shadow root which defeats the purpose of hydration.

I found this out while testing SSR with shadow root; I know you can't declaratively add a shadow root. But I was wondering if moving existing children of the custom element into the shadow root then attempting to hydrate would work? Is there risk of content reflow or style flashing? Is this simply just a limitation of custom elements that cannot be circumvented and therefore not in scope here?

Here's an example:

import { h, Fragment } from 'preact';
import { useState } from 'preact/hooks'
import register from 'preact-custom-element';

export const Counter = ({increment}) => {
	let [ count, setCount ] = useState(0)

	return (
		<>
			<p>Count: {count}</p>

			<button onClick={() => setCount(count + Number(increment))}>Increment by: {increment}</button>
			<button onClick={() => setCount(count - Number(increment))}>Decrement by: {increment}</button>
			<slot />
		</>
	)
}

register(Counter, 'my-counter', ['increment'], { shadow: true })
<my-counter increment="5" hydrate>
	<p>Count: 0</p>
	<button>Increment by: 5</button>
	<button>Decrement by: 5</button>
</my-counter>

These are the results when the script loads:

<my-counter increment="5" hydrate>
	#shadow-root
		<p>Count: 0</p>
		<button>Increment by: 5</button>
		<button>Decrement by: 5</button>
	<p>Count: 0</p>
	<button>Increment by: 5</button>
	<button>Decrement by: 5</button>
</my-counter>

This would be the desired results:

<my-counter increment="5" hydrate>
	#shadow-root
		<p>Count: 0</p>
		<button>Increment by: 5</button>
		<button>Decrement by: 5</button>
</my-counter>

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions