Skip to content
HomePagesHomePages template kit

IslandMarker

Wrap a client component's server-rendered output in the island DOM shape: a layout-invisible custom element carrying the island's key and id, plus a sibling `<script type="application/json">` payload the browser runtime reads the props back out of.

Wrap a client component’s server-rendered output in the island DOM shape: a layout-invisible custom element carrying the island’s key and id, plus a sibling <script type="application/json"> payload the browser runtime reads the props back out of. This is the one place that shape is written — every renderer and every “use client” wrapping goes through it.

Both nodes set suppressHydrationWarning, scoped to themselves (it does not descend, so a real mismatch inside the island still reports). A NESTED island’s marker is rendered on the client as well as the server — that is what lets its parent island’s client render match the markup SSR produced — and islandId comes from useId, which counts from the root of the tree being rendered. The server renders a whole section under an identifierPrefix; the client hydrates a subtree rooted at one marker, with no prefix. The two ids therefore diverge by construction and cannot be reconciled by passing a prefix. That divergence is inert: React leaves the server’s ids in the DOM, the marker and its payload come from the same islandId in one render so they stay paired under either outcome, and a nested marker’s id is never read — hydrateIslands skips nested markers, leaving them to their parent.

No children means no server-rendered output, and the marker says so on itself with data-tr-island-frameless — the browser loader mounts such an island fresh rather than hydrating it against markup that was never emitted.

Import from @homepages/template-kit.

function IslandMarker(props: IslandMarkerProps): ReactNode
Name Type Required Description
{ islandKey, islandId, props, children } IslandMarkerProps required

ReactNode