Skip to content

lit-ui-router-ssr / hydrateRoot

Function: hydrateRoot() ​

ts
function hydrateRoot(
   container, 
   value, 
   options?
): false | (() => void);

Defined in: packages/lit-ui-router-ssr/src/client.ts:621

Adopts a server-rendered container, and the <ui-view>s that wake under it.

The container's hydration signature is read first, and decides whether there is anything to adopt. A container with no signature renders cold, and so does one whose signature names another release line of this package — another minor below 1.0, another major from 1.0 — with a development warning naming both versions, and so does one whose signature no lit-part marker follows, as a comment-stripping minifier leaves it. Each time the container is emptied and this returns false, so the caller's render() draws the page once. A container this adopts keeps its signature.

adoptUiViewContext is provided on container with core's provideContext() first, so a view woken by the walk finds it; hydrate() then runs over container. The walk reaches each <ui-view>'s uiViewSlot part, which wakes that view; the view re-seeks its router, requests the adopter and calls it, which reveals the markers the server prefixed for that view and hydrates the element's own render against them. That hydrate reaches the slot parts of the views nested inside the routed component the same way, parent first. The walk also pins the adopter to every served view it passes: a view the app detaches between the walk and its own update sleeps until it is attached again, and the pin is what adopts it then, after this call's provider is released. A view the walk never reached — one outside container, or one whose attribute the app cleared itself after the release — is answered by nobody: core drops its held nodes and warns in development. An element the render deferred and wrote no marker for is woken once the walk has finished, since nothing in the walk reaches it.

The provider answers synchronously and stops immediate propagation, so an outer provider never answers the same request twice. It outlives this call, because a nested view wakes on its parent's own update rather than inside the root walk. Release it once the page has settled. A second call on the same container throws out of hydrate(), which already holds a live render there, and releases its own provider before rethrowing, so the live one keeps answering.

Each served view that wakes under the walk reports what its wake came to — an AdoptOutcome — once, as a UiViewAdoptEvent dispatched from the view, and to options.onAdopt when given. The pin carries that callback, so a view adopted after the release still reaches it.

A hydrate() that throws is rethrown, over a container emptied the same way. The caller renders into it.

The boot is the router first: router.start(), await its first successful transition, then this call. The walk commits .uiRouter onto <ui-router> and each woken <ui-view> re-seeks the router before its own first render, so the views find the settled router rather than the placeholder they registered against. Nothing constrains when lit-ui-router-ssr/register is imported.

Parameters ​

ParameterTypeDescription
containerHTMLElementthe element the server's markup was written into
valueunknownthe same template the server rendered, with every <ui-view> hole empty
optionsHydrateRootOptionslit render options, passed on to hydrate(), and onAdopt

Returns ​

false | (() => void)

the function that releases the provider, or false, over an emptied container, when there is nothing to adopt — no signature, as on a cold client render or a dev server, one from another release line, or one no render marker follows

Example ​

ts
import { hydrateRoot } from 'lit-ui-router-ssr/client';

await booted;
const release = hydrateRoot(root, page(router));
if (!release) render(page(router), root);