Skip to content

v2.2.0

Latest

Choose a tag to compare

@metonym metonym released this 05 Jul 19:24
· 10 commits to master since this release
v2.2.0
b726a08

Features

  • Add createIntersectionGroup for shared-observer list usage (#138)
  • Add createIntersectionObserver rune-based composable (#139)

Fixes

  • Guard against missing IntersectionObserver support (#137)
  • IntersectionObserver: unobserve the previous element when element becomes null (#143)
  • MultipleIntersectionObserver: unobserve elements when elements becomes empty (#142)
  • createIntersectionGroup: guard against missing IntersectionObserver support (#149)

Performance

  • MultipleIntersectionObserver: use Set-based diffing for the elements array
  • IntersectionObserver: avoid recreating the observer for value-equal threshold, root, or rootMargin (#141)

Usage guide

createIntersectionObserver composable

createIntersectionObserver gets you reactive intersection state without wrapping markup in a component or wiring up your own onobserve callback: call it in <script> for intersecting/entry getters, then apply attach to the node with {@attach}.

<script>
  import { createIntersectionObserver } from "svelte-intersection-observer";

  const observer = createIntersectionObserver(() => ({ threshold: 0.5 }));
</script>

<div {@attach observer.attach}>
  {observer.intersecting ? "In view" : "Not in view"}
</div>

It takes the same options as intersectAttachment (a function returning the options object) and reuses its underlying observer logic — intersecting, entry, and attach are the only things it hands back.

createIntersectionGroup for #each lists

A bare intersect/intersectAttachment inside an #each block creates one native IntersectionObserver per iteration — for a long list, that's N observers instead of 1. createIntersectionGroup fixes this for the action/attachment API: call it once to create a group, then call group.attach(...) once per element to get an attachment that shares a single underlying observer across the whole group.

<script>
  import { createIntersectionGroup } from "svelte-intersection-observer";

  let groupItems = $state(
    Array.from({ length: 5 }, (_, i) => ({ id: i, intersecting: false })),
  );

  const group = createIntersectionGroup();
</script>

{#each groupItems as item (item.id)}
  <div
    class:intersecting={item.intersecting}
    {@attach group.attach({
      onobserve: (entry) => (item.intersecting = entry.isIntersecting),
    })}
  >
    Item {item.id}
  </div>
{/each}

root/rootMargin/threshold configure the one shared observer, so they're passed once to createIntersectionGroup itself rather than per element; once, skip, onobserve, and onintersect are the only options that make sense per element, so those are what group.attach(...) accepts.

Choosing between MultipleIntersectionObserver and createIntersectionGroup

Both share one observer across many elements. Pick based on how you want to wire it up:

  • Use MultipleIntersectionObserver when you're fine wrapping the list in a component and want a ready-made elementIntersections map handed to you via the children snippet.
  • Use createIntersectionGroup when you'd rather attach directly to each element with {@attach}, no extra component, and are happy tracking intersection state on your own per-item objects.

Type imports

import type {
  IntersectGroupNodeOptions,
  IntersectGroupSharedOptions,
  IntersectionGroup,
} from "svelte-intersection-observer/intersect.svelte";
import type { IntersectionObserverState } from "svelte-intersection-observer/create-intersection-observer.svelte";
import {
  createIntersectionGroup,
  createIntersectionObserver,
} from "svelte-intersection-observer";