Hydration
Attach the browser runtime to server-rendered markup, and verify the markup matches before it does.
Example
Keep the route tree shared and change the delivery adapter—not the component contract—when moving between client, server, and static rendering.
import { createSPA, hydrateSPA } from '@askrjs/askr/boot';
const root = document.getElementById('app')!;
if (root.childNodes.length) {
await hydrateSPA({ root, registry });
} else {
await createSPA({ root, registry });
}Adopt server markup
`hydrateSPA` (from `@askrjs/askr/boot`) attaches the client runtime to HTML that a server already rendered, given the same `root` and explicit `registry` used by the server, plus an optional `dataRuntime` for reusing server-fetched data on the client. It's the counterpart to `createSPA`: `createSPA` builds the DOM from scratch, `hydrateSPA` claims DOM that's already there.
Deterministic first render
SSR and hydration share a numeric `seed` (see `createRenderContext(seed, ...)` and `renderToStringSync`'s `seed` option) so that keys and internal ordering generated during server render can be reproduced exactly on the client. Without matching seeds, the client's first pass could generate different keys than the server did, and hydration would treat identical markup as mismatched.
Event attachment
Hydration walks the existing DOM tree and attaches event listeners to the elements the component tree expects, rather than replacing nodes outright. `hydrate.deferUntilIdle` and `hydrate.deferBelowFold` (with `foldThreshold`) on `HydrateSPAConfig` let you push that listener attachment to idle time or until an element scrolls into view, trading immediate interactivity for less main-thread work at load.
Mismatch diagnostics
Set `hydrate: { verifyMarkup: true }` on `hydrateSPA` to have it check server-rendered markup against what the client would produce before attaching to it, surfacing a mismatch instead of silently adopting the wrong structure. `hydrate.skipSelectors` excludes known-divergent regions (third-party widgets, ads) from event-listener attachment and deferred-boundary tracking — it does not exempt those regions from the markup-verification check itself, so a third-party widget that mutates its own markup can still trigger a mismatch there even while listed in `skipSelectors`.