@svelte-put/intersect
Acknowledgement
This packages employs the Svelte action strategy. If you are looking for a declarative, component-oriented solution, check out metonym’s implementation.
Installation
npm install --save-dev @svelte-put/intersect@^3.0.0pnpm add -D @svelte-put/intersect@^3.0.0yarn add -D @svelte-put/intersect@^3.0.0Quick Start
Below is a minimal example with default options. The event listener provided to the intersect CustomEvent will be triggered when the targeted div intersects the viewport.
<script lang="ts">
import { intersect, type IntersectDetail } from '@svelte-put/intersect';
function onIntersect(e: CustomEvent<IntersectDetail>) {
const { observer, entries, direction } = e.detail;
console.log('the observer itself', observer);
console.log('scrolling direction:', direction);
console.log('intersecting:', entries[0]?.isIntersecting ? 'entering' : 'leaving');
}
</script>
<div use:intersect on:intersect={onIntersect} />Initialization Options
intersect can take a config object that supports all options in IntersectionObserver’s constructor (root, rootMargin, threshold), and an additional enabled option to dynamically enable/disable the action.
<script>
import { intersect } from '@svelte-put/intersect';
let root;
</script>
<main bind:this={root}>
<section
use:intersect={{
enabled: true,
root,
rootMargin: '100px 0px 50px 0px',
threshold: [0.2, 0.5, 1],
}}
/>
</main>Intersection CustomEvents
intersect
Listener for the intersect CustomEvent is essentially the same callback as one passed to the IntersectionObserver’s constructor.
intersect will attempt to detect the scrolling direction by keeping record of boundingClientRect. This is available in the event listener via the event.detail.direction property.
<script lang="ts">
import { intersect, type IntersectDetail } from '@svelte-put/intersect';
let detail: IntersectDetail;
function onIntersect(e: CustomEvent<IntersectDetail>) {
detail = e.detail;
}
</script>
<div
class="mx-auto flex h-80 w-4/5 flex-col items-center justify-between bg-blue-200"
use:intersect={{ threshold: 0.5, rootMargin: '-100px 0px 0px' }}
on:intersect={onIntersect}
>
{#each new Array(2) as _}
<p>
{#if detail}
<span>Scrolling {detail.direction}</span> &
<span>{detail.entries[0]?.isIntersecting ? 'entering' : 'leaving'}</span>
{/if}
</p>
{/each}
</div>intersectonce
Following the same interface as with intersect, intersectonce CustomEvent only fires once on the first intersection and never again. One possible use case is for fading-in animation on scroll, as seen in the below example.
<script lang="ts">
import { intersect } from '@svelte-put/intersect';
import { fly } from 'svelte/transition';
let ulElement: HTMLUListElement;
let intersectionMap: Record<string, boolean> = {
one: false,
two: false,
three: false,
four: false,
five: false,
six: false,
seven: false,
eight: false,
};
</script>
<ul
class="max-h-[400px] w-full space-y-40 overflow-hidden overflow-y-auto p-4"
bind:this={ulElement}
>
{#each Object.keys(intersectionMap) as key (key)}
{#key intersectionMap[key]}
<li
class="h-[300px] odd:bg-green-200 even:bg-blue-200 marker:content-none"
class:invisible={!intersectionMap[key]}
in:fly={{ y: 100, duration: 250 }}
use:intersect={{ threshold: 0.4, root: ulElement }}
on:intersectonce={() => (intersectionMap[key] = true)}
/>
{/key}
{/each}
</ul>Happy intersecting! 👨💻