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

hydro-dom

v1.1.2

Published

Minimal hydration library

Readme

Hydro

Hydro is a minimalistic JavaScript library for bringing interactivity to server-side rendered web applications. It implements the Islands Architecture, allowing you to keep your fast, SEO-friendly HTML while hydrating only the specific components that need client-side logic.

Think of it as "Mini-Astro" for any backend, whether you use Go, Rust, Node, or PHP. Hydro provides a powerful, signal-based reactivity system (inspired by SolidJS) without forcing you into a heavy framework. It is the perfect companion for htmx and traditional templating engines.

Features

  • Backend agnostic
  • Dynamic hydration
  • DOM helpers
  • Fine grained reactivity
  • Compatibility with other frameworks
  • 2.2 KB bundle size (minified + gziped)

Installation

via CDN:

<script src="https://cdn.jsdelivr.net/npm/hydro-dom@latest/dist/cdn.min.js"></script>

via npm:

npm i hydro-dom

then import it with:

import Hydro from 'hydro-dom';

Usage

Components & Hydration

Components are the core of Hydro. They represent interactive regions (islands) in your website.

You can register a component by calling component(name, initHook). The function accepts two arguments. First the name of the component and second a callback defining the behaviour of the component. The callback provides a ComponentRef and props.

<div data-comp="counter"></div>

The counter component defines behaviour for all islands with data-comp="counter".

Hydro.component("counter", (ref, props) => {
    // Behaviour ...
});

In our context, hydrating means that defined behaviour (components) get initialized and attached to DOM elements.

Hydrate all unhydrated components in the DOM:

// Usually you will call hydrate when the DOM has been loaded 
Hydro.hydrate();

Or hydrate just a specific part of the DOM tree:

const counter = document.getElementById("counter")
Hydro.hydrate(counter);

Destroy hydrated components (will clean up effects, event listeners, timeouts, etc.):

Hydro.destroy(); // Destroys all hydrated components in the DOM tree

// Or

Hydro.destroy(counter); // Destroys a subtree

Props

Since this library is designed for SSR, data gets already rendered to html on the backend. But if we want to access this data we would have to parse the html which is unpractical. Therefore you can attatch json to html elements on the server and read it on the client:

<div data-comp="counter" data-props='{"count": {{ count }} }'>
    <button>Add 1</button>
    <div class="display">{{ count }}</div>
</div>
Hydro.component("notes", (ref, props) => {
    console.log(`Count from backend: ${props.count}`);
});

Element quering & Element wrappers

Retreive the component's root element (the one that has data-comp="...") by calling ComponentRef.root(). Select a single element with ComponentRef.$(selector) or multiple elements with ComponentRef.$$(selector). These elements must be descendents of the root element or the root element itself.

ComponentRef.root(), ComponentRef.$(selector) and ComponentRef.$$(selector) won't return elements directly. They return wrapper. Element wrappers provide helpers such has getters and setters or event listeners.

Hydro.component("dropdown", (ref, props) => {
    let isOpen = props.isOpen || false; // Use props to retreive initial state

    const button = ref.$("button");
    
    button.on("click", () => {
        isOpen = !isOpen;
        button.setText(isOpen ? "Close" : "Open");

        if (isOpen) {
            ref.$(".content").removeAttr("hidden");
        } else {
            ref.$(".content").setAttr("hidden", true);
        }
    });
});

Reactivity

It is easy to lose track of a component's state when using getters, setters and listenrs. Signals solve this problem:

Hydro provides a fine grained reactivity system similar to that of SolidJS. You can create reactive getters and setters with signal() and bind them to DOM state with methods such as bindText() and bindAttr().

Hydro.component("dropdown", (ref) => {
    const [open, setOpen] = Hydro.signal(false);
    const buttonText = Hydro.computed(() => open() ? "Close" : "Open");

    ref.$("button")
        .bindText(buttonText())
        .on("click", () => setOpen(prev => !prev));

    ref.$(".content").bindShow(open);
});

Usage with htmx

Combining Hydro with htmx is quite simple, just add these two listeners:

document.addEventListener("htmx:load", (e) => {
    Hydro.hydrate(e.target);
})

document.addEventListener("htmx:beforeSwap", (e) => {
    Hydro.destroy(e.target);
});

Contributors

Contibutions are welcome.

License

MIT License