npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-lazy-hydration-hook

v1.1.0

Published

A React hook/HOC to lazy hydrate components on user interaction (hover, focus, keyboard)

Readme

React Lazy Hydration Hook (react-lazy-hydration-hook)

A lightweight, high-performance React hook and Higher-Order Component (HOC) designed for lazy hydration of server-rendered (SSR) components.

npm version License: MIT


🚀 Installation

Via npm:

npm install react-lazy-hydration-hook

Via yarn:

yarn add react-lazy-hydration-hook

Via pnpm:

pnpm add react-lazy-hydration-hook

⚡ What is it & Why use it?

Standard Server-Side Rendering (SSR) generates 100% of your HTML on the server, which is great for SEO and initial visual paint.

However, once the page arrives in the browser, React executes Full Hydration:

  1. React traverses 100% of the DOM tree generated by the server.
  2. It instantiates internal component states and attaches event listeners to every single node.
  3. The Problem: On complex pages (e.g. e-commerce grids, product feeds, footers, customer reviews), this initial JavaScript execution freezes the Main Thread and degrades key Core Web Vitals metrics (INP - Interaction to Next Paint, TBT - Total Blocking Time).

The Solution: useStatic (Islands Architecture)

useStatic defers client-side hydration until the user actually interacts with a specific component (hover, click, focus, or keyboard event).

  • 100% SEO & SSR Preserved: The HTML generated on the server remains intact and fully visible to search engines.
  • Instant Interactivity: The browser doesn't execute unnecessary JavaScript for off-screen or unvisited components on page load.

📈 Real-World Performance Benchmarks

Tested using hydrateRoot (React 18/19) in a real client DOM environment with 500 complex components:

| Metric / Benchmark | Standard React Hydration | Deferred Hydration (useStatic) | Performance Impact | | :--- | :--- | :--- | :--- | | Initial Hydration Time (Page Load) | 7.53 ms | 1.35 ms | 🚀 +82.1% Faster Initial Interactivity | | Active React Memory Nodes at Boot | 500 / 500 nodes | 0 / 500 nodes | 📉 -100% initial JavaScript execution overhead | | Server HTML Output Size | 100% complete | 100% complete | ✅ 0% Loss in SEO or DOM Structure | | Main Thread Blocking (TBT) | Heavy load spikes | Free for smooth scrolling | 🟢 100/100 Core Web Vitals Potential |

Benchmark conducted using JSDOM client emulation on 500 nested interactive components.


⚙️ How It Works Under the Hood

  1. Server-Side Rendering (SSR): Your component renders normally on the server, producing standard HTML (e.g. <button>Click</button>).
  2. Client-Side Bypass: On initial page load, useStatic renders a memoized wrapper (SafeStaticHTML) with suppressHydrationWarning and empty inner HTML. React skips DOM reconciliation for this tree, keeping the server-rendered HTML intact.
  3. Event Interception: A lightweight native event listener (pointerover, focusin, keydown) is attached to the wrapper element.
  4. On-Demand Hydration: As soon as the user hovers or interacts with the element, React hydrates the full component tree and attaches interactive handlers seamlessly.

🛠️ Usage & Examples

1. Basic Usage (Lazy Hydration on Hover / Focus)

import { useStatic } from 'react-lazy-hydration-hook';

// A heavy component (e.g., product card, reviews list, comments section)
function CustomerReviews() {
  return (
    <div className="reviews-container">
      <h2>Customer Reviews (50+)</h2>
      {/* Heavy rendering logic */}
    </div>
  );
}

// Wrap it with useStatic
export const LazyCustomerReviews = useStatic(CustomerReviews, {
  on: ['pointerover', 'focusin', 'click'],
});

2. Static Only Components (ssrOnly)

For components that render pure HTML and never need client-side React state or click handlers (e.g. Technical Specs, Legal Footers, Static Descriptions):

import { useStatic } from 'react-lazy-hydration-hook';
import TechnicalSpecifications from './TechnicalSpecifications';

// Never hydrates on the client, saving 100% of JS execution cost forever
export const StaticSpecs = useStatic(TechnicalSpecifications, {
  ssrOnly: true,
});

3. Custom Wrapper Element & Hydration Callbacks

import { useStatic } from 'react-lazy-hydration-hook';
import HeavyWidget from './HeavyWidget';

export const CustomWidget = useStatic(HeavyWidget, {
  on: 'click',
  noWrapper: 'article', // Use <article> wrapper tag instead of <div>
  wrapperProps: { className: 'widget-container', id: 'my-widget' },
  didHydrate: () => {
    console.log('HeavyWidget has been successfully hydrated on demand!');
  },
});

📖 API Reference

useStatic(Component, options?)

Options (LazyHydrationOptions)

| Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | on | string \| string[] | ['pointerover', 'pointerdown', 'focusin', 'keydown', 'click'] | DOM event(s) that trigger client-side hydration. | | ssrOnly | boolean | false | When true, the component renders on the server but never hydrates on the client. | | noWrapper | boolean \| string | false | Customizes the HTML tag wrapper (e.g. 'span', 'article'). | | wrapperProps | React.HTMLAttributes | {} | Props passed to the wrapper HTML element (className, id, etc.). | | didHydrate | () => void | undefined | Callback fired immediately after hydration completes. |


🎯 Ideal Use Cases

  • E-Commerce Product Pages: Keep reviews, recommendations, and specs static until hover.
  • Infinite Scroll & Long Feeds: Defer hydration of off-screen feed posts.
  • Footers & Sidebars: Prevent heavy secondary navigation from blocking initial load.
  • Modals & Tooltips: Hydrate interactive overlays only when triggered.

📄 License

MIT © morganluc-ops