UNPKG

svelte-intersection-observer

Version:

Detect if an element is in the viewport using the Intersection Observer API

221 lines (165 loc) 6.92 kB
# svelte-intersection-observer [![NPM][npm]][npm-url] > Detect if an element is in the viewport using the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). <!-- REPO_URL --> Try it in the [Svelte REPL](https://svelte.dev/repl/8cd2327a580c4f429c71f7df999bd51d). <!-- TOC --> ## Installation **Yarn** ```bash yarn add -D svelte-intersection-observer ``` **NPM** ```bash npm i -D svelte-intersection-observer ``` **pnpm** ```bash pnpm i -D svelte-intersection-observer ``` ## Usage ### Basic Use the [`bind:this`](https://svelte.dev/docs#bind_element) directive to pass an element reference to the `IntersectionObserver` component. Then, simply bind to the reactive `intersecting` prop to determine if the element intersects the viewport. ```svelte <script> import IntersectionObserver from "svelte-intersection-observer"; let element; let intersecting; </script> <header class:intersecting> {intersecting ? "Element is in view" : "Element is not in view"} </header> <IntersectionObserver {element} bind:intersecting> <div bind:this={element}>Hello world</div> </IntersectionObserver> ``` ### Once Set `once` to `true` for the intersection event to occur only once. The `element` will be unobserved after the first intersection event occurs. ```svelte <script> import IntersectionObserver from "svelte-intersection-observer"; let elementOnce; let intersectOnce; </script> <header class:intersecting={intersectOnce}> {intersectOnce ? "Element is in view" : "Element is not in view"} </header> <IntersectionObserver once element={elementOnce} bind:intersecting={intersectOnce} > <div bind:this={elementOnce}>Hello world</div> </IntersectionObserver> ``` ### `let:intersecting` An alternative to binding to the `intersecting` prop is to use the `let:` directive. In the following example, the "Hello world" element will fade in when its containing element intersects the viewport. ```svelte <script> import IntersectionObserver from "svelte-intersection-observer"; import { fade } from "svelte/transition"; let node; </script> <header /> <IntersectionObserver element={node} let:intersecting> <div bind:this={node}> {#if intersecting} <div transition:fade={{ delay: 200 }}>Hello world</div> {/if} </div> </IntersectionObserver> ``` ### `on:observe` event The `observe` event is dispatched when the element is first observed and also whenever an intersection event occurs. ```svelte no-eval <IntersectionObserver {element} on:observe={(e) => { console.log(e.detail); // IntersectionObserverEntry console.log(e.detail.isIntersecting); // true | false }} > <div bind:this={element}>Hello world</div> </IntersectionObserver> ``` ### `on:intersect` event As an alternative to binding the `intersecting` prop, you can listen to the `intersect` event that is dispatched if the observed element is intersecting the viewport. **Note**: Compared to `on:observe`, `on:intersect` is dispatched only when the element is _intersecting the viewport_. In other words, `e.detail.isIntersecting` will only be `true`. ```svelte no-eval <IntersectionObserver {element} on:intersect={(e) => { console.log(e.detail); // IntersectionObserverEntry console.log(e.detail.isIntersecting); // true }} > <div bind:this={element}>Hello world</div> </IntersectionObserver> ``` ## API ### Props | Name | Description | Type | Default value | | :----------- | :---------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------- | :------------ | | element | Observed element | `HTMLElement` | `null` | | once | Unobserve the element after the first intersection event | `boolean` | `false` | | intersecting | `true` if the observed element is intersecting the viewport | `boolean` | `false` | | root | Containing element | `null` or `HTMLElement` | `null` | | rootMargin | Margin offset of the containing element | `string` | `"0px"` | | threshold | Percentage of element visibile to trigger an event | `number` between 0 and 1, or an array of `number`s between 0 and 1 | `0` | | entry | Observed element metadata | [`IntersectionObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) | `null` | | observer | `IntersectionObserver` instance | [`IntersectionObserver`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver) | `null` | ### Dispatched events - **on:observe**: fired when the element is first observed or whenever an intersection change occurs - **on:intersect**: fired when the element is intersecting the viewport The `e.detail` dispatched by the `observe` and `intersect` events is an [`IntersectionObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) interface. Note that all properties in `IntersectionObserverEntry` are read-only. <details> <summary><code>IntersectionObserverEntry</code></summary> ```ts interface IntersectionObserverEntry { target: HTMLElement; time: number; isIntersecting: boolean; isVisible: boolean; intersectionRatio: number; intersectionRect: { bottom: number; height: number; left: number; right: number; top: number; width: number; x: number; y: number; }; rootBounds: { bottom: number; height: number; left: number; right: number; top: number; width: number; x: number; y: number; }; boundingClientRect: { bottom: number; height: number; left: number; right: number; top: number; width: number; x: number; y: number; }; } ``` </details> ## Changelog [Changelog](CHANGELOG.md) ## License [MIT](LICENSE) [npm]: https://img.shields.io/npm/v/svelte-intersection-observer.svg?color=%23ff3e00&style=for-the-badge [npm-url]: https://npmjs.com/package/svelte-intersection-observer