Detect if an element is in the viewport using the Intersection Observer API.
Try it in the Svelte REPL.
# NPM
npm i svelte-intersection-observer
# pnpm
pnpm i svelte-intersection-observer
# Bun
bun i svelte-intersection-observer
# Yarn
yarn add 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.
<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>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>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>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>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>| Name | Description | Type | Default value | 
|---|---|---|---|
| element | Observed element | HTMLElement | null | 
| once | Unobserve the element after the first intersection event | boolean | false | 
| intersecting | trueif the observed element is intersecting the viewport | boolean | false | 
| root | Containing element | nullorHTMLElement | null | 
| rootMargin | Margin offset of the containing element | string | "0px" | 
| threshold | Percentage of element visibile to trigger an event | numberbetween 0 and 1, or an array ofnumbers between 0 and 1 | 0 | 
| entry | Observed element metadata | IntersectionObserverEntry | null | 
| observer | IntersectionObserverinstance | IntersectionObserver | null | 
- 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;
  };
}