diff --git a/.changeset/stupid-peas-juggle.md b/.changeset/stupid-peas-juggle.md new file mode 100644 index 000000000000..1e01c0996636 --- /dev/null +++ b/.changeset/stupid-peas-juggle.md @@ -0,0 +1,10 @@ +--- +'astro': minor +--- + +Extends the `client:visible` directive by adding an optional `rootMargin` property. This allows a component to be hydrated when it is close to the viewport instead of waiting for it to become visible. + +```html + + +``` diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index e9c73fc90f3a..ed6015757cc9 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -70,7 +70,7 @@ export interface AstroBuiltinProps { 'client:load'?: boolean; 'client:idle'?: boolean; 'client:media'?: string; - 'client:visible'?: boolean; + 'client:visible'?: string|boolean; 'client:only'?: boolean | string; } diff --git a/packages/astro/src/runtime/client/visible.ts b/packages/astro/src/runtime/client/visible.ts index de36b29098a5..9e625ca23df9 100644 --- a/packages/astro/src/runtime/client/visible.ts +++ b/packages/astro/src/runtime/client/visible.ts @@ -5,12 +5,16 @@ import type { ClientDirective } from '../../@types/astro.js'; * We target the children because `astro-island` is set to `display: contents` * which doesn't work with IntersectionObserver */ -const visibleDirective: ClientDirective = (load, _options, el) => { +const visibleDirective: ClientDirective = (load, options, el) => { const cb = async () => { const hydrate = await load(); await hydrate(); }; + const ioOptions = { + rootMargin: typeof options.value === 'string' ? options.value : undefined, + }; + const io = new IntersectionObserver((entries) => { for (const entry of entries) { if (!entry.isIntersecting) continue; @@ -19,7 +23,7 @@ const visibleDirective: ClientDirective = (load, _options, el) => { cb(); break; // break loop on first match } - }); + }, ioOptions); for (const child of el.children) { io.observe(child);