Skip to content

metonym/svelte-intersection-observer

Repository files navigation

svelte-intersection-observer

NPM

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

Try it in the Svelte REPL.

Installation

# NPM
npm i svelte-intersection-observer

# pnpm
pnpm i svelte-intersection-observer

# Bun
bun i svelte-intersection-observer

# Yarn
yarn add svelte-intersection-observer

Usage

Basic

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.

<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.

<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.

<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.

<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.

<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 numbers between 0 and 1 0
entry Observed element metadata IntersectionObserverEntry null
observer IntersectionObserver instance 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.

Note that all properties in IntersectionObserverEntry are read-only.

IntersectionObserverEntry
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;
  };
}

Changelog

Changelog

License

MIT