Detect if an element is in the viewport using the Intersection Observer API
npm install svelte-intersection-observer[![NPM][npm]][npm-url]
> Detect if an element is in the viewport using the Intersection Observer API.
Try it in the Svelte REPL.
``shNPM
npm i svelte-intersection-observer
`
Use the bind:this 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
{intersecting ? "Element is in view" : "Element is not in view"}
Hello world
`
Set once to true for the intersection event to occur only once. The element will be unobserved after the first intersection event occurs.
`svelte
{intersectOnce ? "Element is in view" : "Element is not in view"}
element={elementOnce}
bind:intersecting={intersectOnce}
>
$3
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
{#if intersecting}
Hello world
{/if}
`$3
The
observe event is dispatched when the element is first observed and also whenever an intersection event occurs.`svelte no-eval
{element}
on:observe={(e) => {
console.log(e.detail); // IntersectionObserverEntry
console.log(e.detail.isIntersecting); // true | false
}}
>
Hello world
`$3
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
{element}
on:intersect={(e) => {
console.log(e.detail); // IntersectionObserverEntry
console.log(e.detail.isIntersecting); // true
}}
>
Hello world
`$3
For performance, use
MultipleIntersectionObserver to observe multiple elements.This avoids instantiating a new observer for every element.
`svelte
Item 1: {elementIntersections.get(ref1) ? "✓" : "✗"}
Item 2: {elementIntersections.get(ref2) ? "✓" : "✗"}
Item 1
Item 2
`API
$3
#### Props
| Name | Description | Type | Default value |
| :----------- | :---------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------ | :------------ |
| element | Observed element |
null or 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 visibility to trigger an event | number between 0 and 1, or an array of numbers between 0 and 1 | 0 |
| entry | Observed element metadata | null or IntersectionObserverEntry | null |
| observer | IntersectionObserver instance | null or 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 interface.#### Slot props
| Name | Type |
| :----------- | :------------------------------------------------------------------------------------------------------------------ |
| intersecting |
boolean |
| entry | null or IntersectionObserverEntry |
| observer | IntersectionObserver |$3
#### Props
| Name | Description | Type | Default value |
| :------------------- | :---------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------- | :------------ |
| elements | Array of HTML elements to observe |
Array | [] |
| once | Unobserve elements after the first intersection event | boolean | false |
| root | Containing element | null or HTMLElement | null |
| rootMargin | Margin offset of the containing element | string | "0px" |
| threshold | Percentage of element visibility to trigger an event | number between 0 and 1, or an array of numbers between 0 and 1 | 0 |
| elementIntersections | Map of each element to its intersection state | Map | new Map() |
| elementEntries | Map of each element to its latest entry | Map> | new Map() |
| observer | IntersectionObserver instance | null or IntersectionObserver | null |#### Dispatched events
- on:observe: fired when an element is first observed or whenever an intersection change occurs
- on:intersect: fired when an element is intersecting the viewport
The
e.detail for both events includes:`ts
{
entry: IntersectionObserverEntry;
target: HTMLElement;
}
`#### Slot props
| Name | Type |
| :------------------- | :-------------------------------------------------------------------------------------------------------------------------------------- |
| observer |
IntersectionObserver |
| elementIntersections | Map |
| elementEntries | Map> |$3
Note that all properties in IntersectionObserverEntry are read-only.
IntersectionObserverEntry
`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;
};
}
``[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