The zudo-react runtime
How zfb uses one owned runtime to render whole documents and adopt island subtrees.
zfb uses one rendering runtime: zudo-react, shipped as subpath exports of @takazudo/zfb. JSX remains the authoring syntax, while the runtime defines how descriptions become HTML and how an island takes ownership of its existing HTML in the browser. There is no framework selector or adapter layer.
One runtime on both sides
The engine needs three connected capabilities from zudo-react:
A synchronous server renderer for the whole document. The server entry accepts the completed page description and returns an HTML string. zfb may await the page function before rendering, but rendering the resulting tree is synchronous.
A client entry that adopts an island subtree. The client entry receives the component description, its wrapper element, and the expected component and build identity.
hydratechecks and adopts the server DOM;mountcreates a new client subtree when no server-rendered child DOM should be adopted.Island glue that carries zfb's boundary metadata into those calls. The
<Island>wrapper stays in the document as adiv. Itsdata-zfb-island*attributes identify the component and the wrapper; the transport, protocol, build, and JSON props attributes let the client verify that it is adopting the matching output. Runtime comment regions are local to the child subtree and do not mark the rest of the page.
The public entries make those roles explicit:
import { signal } from "@takazudo/zfb/zudo-react";
import { renderToString } from "@takazudo/zfb/zudo-react/server";
import { hydrate, mount } from "@takazudo/zfb/zudo-react/client";Components run once during setup. Signals provide live values, and scoped effects and cleanup own browser work for that component instance. See the zudo-react overview for the component model and the rest of the runtime API.
Island lifecycle
The generated client manifest exposes one mount function per registered component. Its final contract is mount(props, element, mode: "hydrate" | "render") => RootHandle | null. hydrate means adopt the child DOM already inside the wrapper; render means create a fresh child subtree. A failed preflight or mount returns null and leaves the server markup inert rather than silently switching modes.
The returned handle separates resource release from DOM removal. dispose() stops effects, subscriptions, and listeners while leaving the child DOM in place, so zfb can replace a page body without deleting content on its own. unmount() disposes the root and removes the child nodes owned by that handle; the zfb wrapper remains. When a persisted island's component or props change, zfb disposes its old root and uses render for the replacement. Unchanged persisted roots keep their DOM and live state.
One JSX dialect
Consumers set jsxImportSource to @takazudo/. The runtime uses HTML and SVG attribute spellings such as class and for, function listeners such as on:click, and an explicit rawHtml prop for content the caller already trusts. Signals replace render-time state hooks: a component creates its state once, and the renderer updates the bindings that use it. This is a small, owned runtime rather than a compatibility facade; existing framework components need to be rewritten to its API.
For the zfb side of scheduling, persisted wrappers, and server-to-client props, see Islands. For the exact description, prop, and hydration rules, see the Island API.