---
url: >-
  https://lit-ui-router.dev/reference/lit-ui-router-ssr/client/functions/hydrateRoot.md
---
[lit-ui-router-ssr](../../index.md) / [client](../index.md) / hydrateRoot

# Function: hydrateRoot()

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

Defined in: [packages/lit-ui-router-ssr/src/client.ts:846](https://github.com/simshanith/lit-ui-router/blob/6e47ef8d8a4b24e99c074fb5c8c9cfaddfdb36a4/packages/lit-ui-router-ssr/src/client.ts#L846)

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

The container's [hydration signature](readHydrationSignature.md) 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](../variables/adoptUiViewContext.md) 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](../variables/uiViewSlot.md) 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 — except
one inside a `<ui-view>`, which wakes once that view has hydrated its own
render, so a routed element never wakes ahead of the view that routes 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](../type-aliases/AdoptOutcome.md) — once, as a [UiViewAdoptEvent](../type-aliases/UiViewAdoptEvent.md) 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.

[bootstrap](bootstrap.md) runs the whole boot around this call. Called directly, the
boot is the router first: `seed` the router with [readResolvePayload](readResolvePayload.md),
`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

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `container` | `HTMLElement` | the element the server's markup was written into |
| `value` | `unknown` | the same template the server rendered, with every `<ui-view>` hole empty |
| `options?` | [`HydrateRootOptions`](../interfaces/HydrateRootOptions.md) | lit 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';
import { render, type TemplateResult } from 'lit';
import type { UIRouterLit } from 'lit-ui-router';

declare const booted: Promise<void>;
declare const root: HTMLElement;
declare const router: UIRouterLit;
declare function page(router: UIRouterLit): TemplateResult;

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