Hydration
The server adapter writes a <template shadowrootmode="open"> inside the
custom element. The browser turns that template into a shadow root while it
parses the page, before it runs the component bundle.
This path requires Svelte’s default open shadow root. Do not set
customElement.shadow to "none" on a server-rendered component. Svelte then
mounts into the light DOM and cannot adopt the declarative shadow root.
After the component bundle loads, Svelte’s generated element class calls
attachShadow(). The browser would
clear and return a matching declarative shadow root.
svebcomponents intercepts that call through Svelte’s public
customElement.extend
option and returns the existing root before the browser clears it. The
extension then calls Svelte’s
hydrate()
function with the server-rendered root.
What hydration preserves
Section titled “What hydration preserves”Svelte adopts the existing shadow DOM if the client and server output match. The server-rendered nodes stay in place throughout hydration.
Before Svelte hydrates, the svebcomponents extension collects:
- attributes on the custom element
- rich properties that the server renderer serializes into the shadow root
- properties assigned before the element upgraded
Property updates and configured attribute reflection continue after hydration. The extension removes the serialized property payload from the shadow root.
Fallbacks
Section titled “Fallbacks”The element uses Svelte’s mount path when it cannot hydrate:
| Situation | Result |
|---|---|
| The server did not provide a declarative shadow root | Svelte mounts the component in an empty root. |
The component declares a <slot> | svebcomponents clears the server content, then Svelte mounts the component. |
| The element reconnects after Svelte tore it down | Svelte mounts a new component instance. |
| Client and server structure differ | Svelte reports the mismatch and mounts fresh output. |
Fallbacks that start with server content replace it.
Limitations
Section titled “Limitations”Svelte 5 compiles <slot> in custom-element mode through a legacy transform
that does not support this hydration path. Slotted components still receive
server-rendered shadow DOM, then re-render when the element upgrades. Dev mode
logs the fallback.
Events
Section titled “Events”Events dispatched through
$host() fire on the custom element
after hydration. Set bubbles: true on the event when it must bubble through
ancestor elements. The hydration host does not forward events created with
createEventDispatcher.
Exported functions
Section titled “Exported functions”The hydration host does not expose component functions as methods on the custom element.
Disable hydration
Section titled “Disable hydration”Set hydratable: false for a client-mounting package:
import { defineConfig } from "@svebcomponents/build";
export default defineConfig({ hydratable: false,});To supply your own element extension, set extend in
<svelte:options customElement={{ ... }}>. Auto-options detects that extension
and skips its hydration injection.