defer-hydration

Defers hydration of heavy React subtrees past first paint using a gated Suspense boundary.

Updated Nov 7, 2025
One-click install
npx skills add https://github.com/rangojs/rango --skill defer-hydration-rangojs
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: defer-hydration
Source: https://github.com/rangojs/rango/tree/main/packages/rangojs-router/skills/defer-hydration
Command: npx skills add https://github.com/rangojs/rango --skill defer-hydration-rangojs

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve? Partial prerendering (PPR) makes first paint instant, but React still hydrates the whole page as one long synchronous main-thread task, leaving the page unresponsive for seconds. A plain Suspense boundary fixes hydration timing but bakes an empty hole into the frozen prelude, losing the body HTML from first paint. ## Core Features & Use Cases - Gated Suspense boundary: A ~40-line client component that keeps the full body HTML in the PPR prelude by using the content as its own fallback, then releases hydration on first idle at retry-lane priority. - Measured main-thread relief: Cuts the worst main-thread task from 2543ms to 386ms and total blocked time from 2705ms to 554ms on a production storefront homepage. - Sync-update trap guidance: Documents why post-hydration state syncs (basket, auth from storage) must be wrapped in startTransition to avoid force-hydrating the boundary synchronously. - Use Case: A content-heavy e-commerce homepage paints instantly from a cached shell but ignores clicks for seconds; wrap the page body in DeferredHydration so the header and nav hydrate immediately while the body hydrates after first idle. ## Quick Start Copy the DeferredHydration component into your app and wrap the heavy page body subtree with it while keeping the interactive chrome outside the boundary.

Frequently Asked Questions about defer-hydration

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I defer hydration of a heavy React component?

Wrap the heavy subtree in a gated Suspense boundary whose fallback is the children themselves, with a client gate that suspends until released on requestIdleCallback. React skips hydrating the boundary, keeps the server DOM visible, and hydrates it in place after first idle.

Why does a Suspense boundary leave an empty hole in PPR prerendering?

Shell capture aborts after a byte-quiet window, so any large subtree under a Suspense boundary postpones and the frozen prelude bakes an empty placeholder. Using the content as the fallback makes the postponed boundary's baked fallback carry the real markup.

Does deferred hydration work with React Server Components and PPR?

Yes, the recipe is designed for PPR shells and uses plain React with no framework imports. The content-as-fallback pattern exploits the postpone mechanics so the body HTML ships in the prelude while hydration is deferred.

Why does my page blank out when state updates after hydration?

A synchronous update reaching into a dehydrated boundary forces React to abandon hydration and client-render the fallback. Wrap post-hydration state syncs like basket or auth reads in startTransition so the boundary is not force-hydrated synchronously.

What are the limitations of deferred hydration with content-as-fallback?

The gated subtree's HTML ships twice on a shell HIT, once as the baked fallback and once as the resumed hole content, adding roughly 29 percent gzipped bytes on a measured homepage. On small pages the extra bandwidth may outweigh the hydration savings.