lazy-hydration

Defers custom element JavaScript out of the initial bundle until the element nears the viewport.

Updated Sep 6, 2026
One-click install
npx skills add https://github.com/malikkotb/shellpluscore --skill lazy-hydration-malikkotb
Or copy as Structured Prompt for Agent▼
Please help me install this Agent Skill.
Skill: lazy-hydration
Source: https://github.com/malikkotb/shellpluscore/tree/main/.agents/skills/lazy-hydration
Command: npx skills add https://github.com/malikkotb/shellpluscore --skill lazy-hydration-malikkotb

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve? Vanilla custom elements in Astro pages bundle their JavaScript into the page's entry chunk and run it on load, even for interaction-gated UI like modals, dropdowns, and media players. This bloats the initial JavaScript of public pages, and Astro's client:* directives do not apply to vanilla custom elements. ## Core Features & Use Cases - Code-split hydration: Replaces eager import "./NameElement" with lazyCustomElement(hostSelector, () => import("./NameElement")) from src/lib/lazy-hydrate.ts, splitting the element and heavy dependencies like GSAP or Mux into a separate chunk. - Visibility-based loading: Uses an IntersectionObserver with a 256px rootMargin so the module loads before a tap lands, which is touch-safe unlike hover intent. - View-transition support: Re-observes on astro:page-load so deferred elements keep working across navigations without extra wiring. - Use Case: Defer the @mux/mux-player bundle in SanityMuxVideo.astro so the heaviest media dependency loads only when the video approaches the viewport. ## Quick Start Ask the AI to convert a component's eager custom element import into a lazyCustomElement call in its .astro script so the module loads only when its trigger nears the viewport.

Frequently Asked Questions about lazy-hydration

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

FAQPage Schema
How do I lazy load a custom element in Astro?▼

Replace the eager `import "./NameElement"` in the component's .astro script with `lazyCustomElement("name-tag", () => import("./NameElement"))` from src/lib/lazy-hydrate.ts. The dynamic import code-splits the element into its own chunk, loaded by an IntersectionObserver when the host nears the viewport.

Why don't Astro client:visible directives work on custom elements?▼

Astro's client:* directives only apply to UI-framework components like React, Vue, Svelte, or Lit that use a renderer. Vanilla custom elements have no renderer, so hydration must be handled manually with a helper like lazyCustomElement.

When should I not defer a custom element's JavaScript?▼

Load eagerly when behavior must be live before any interaction: above-the-fold reveal animations, always-running marquees, smooth scroll, page transitions, and sticky chrome. Deferring these would leave them unarmed at first paint.

Why use IntersectionObserver instead of hover intent for hydration?▼

Hover intent fails on touch devices where there is no hover, and pointerdown races the first tap. Observing visibility with a 256px rootMargin guarantees the module is loaded before a tap can land on the trigger.

Does lazy hydration still work after Astro view transitions?▼

Yes. The lazyCustomElement helper re-observes on astro:page-load, so deferred elements keep working across view-transition navigations even though a bundled module script executes only once per session. Do not add your own astro:page-load wiring.