A range of IntersectionObserver API utilities great for different types of use cases:
createIntersectionObserver- A reactive observer primitive.createViewportObserver- More advanced tracker that creates a store of element signals.createVisibilityObserver- Basic visibility observer using a signal.
npm install @solid-primitives/intersection-observer
# or
pnpm add @solid-primitives/intersection-observer
# or
yarn add @solid-primitives/intersection-observerimport { createIntersectionObserver } from "@solid-primitives/intersection-observer";
const [targets, setTargets] = createSignal<Element[]>([some_element]);
createIntersectionObserver(els, entries => {
entries.forEach(e => console.log(e.isIntersecting));
});
<div ref={el => setTargets(p => [...p, el])} />;function createIntersectionObserver(
elements: Accessor<Element[]>,
onChange: IntersectionObserverCallback,
options?: IntersectionObserverInit,
): void;This primitive comes with a number of flexible options. You can specify a callback at the root with an array of elements or individual callbacks for individual elements.
import { createViewportObserver } from '@solid-primitives/intersection-observer';
// Basic usage:
const [add, { remove, start, stop, instance }] = createViewportObserver(els, e => {...});
add(el, e => console.log(e.isIntersecting))
// Directive usage:
const [intersectionObserver] = createViewportObserver()
<div use:intersectionObserver={(e) => console.log(e.isIntersecting)}></div>function createViewportObserver(
elements: MaybeAccessor<Element[]>,
callback: EntryCallback,
options?: IntersectionObserverInit,
): CreateViewportObserverReturnValue;
function createViewportObserver(
initial: MaybeAccessor<[Element, EntryCallback][]>,
options?: IntersectionObserverInit,
): CreateViewportObserverReturnValue;
function createViewportObserver(
options?: IntersectionObserverInit,
): CreateViewportObserverReturnValue;Creates reactive signal that changes when a single element's visibility changes.
createVisibilityObserver takes a IntersectionObserverInit object as the first argument. Use it to set thresholds, margins, and other options.
root— The Element or Document whose bounds are used as the bounding box when testing for intersection.rootMargin— A string which specifies a set of offsets to add to the root's bounding_box when calculating intersections, effectively shrinking or growing the root for calculation purposes.threshold— Either a single number or an array of numbers between 0.0 and 1.0, specifying a ratio of intersection area to total bounding box area for the observed target.initialValue— Initial value of the signal (default: false)
It returns a configured "use" function for creating a visibility signal for a single element. The passed element can be a reactive signal or a DOM element. Returning a falsy value will remove the element from the observer.
import { createVisibilityObserver } from "@solid-primitives/intersection-observer";
let el: HTMLDivElement | undefined;
const useVisibilityObserver = createVisibilityObserver({ threshold: 0.8 });
// make sure that you pass the element reference in a thunk if it is undefined initially
const visible = useVisibilityObserver(() => el);
<div ref={el}>{visible() ? "Visible" : "Hidden"}</div>;You can use this shorthand when creating a visibility signal for a single element:
let el: HTMLDivElement | undefined;
const visible = createVisibilityObserver({ threshold: 0.8 })(() => el);
<div ref={el}>{visible() ? "Visible" : "Hidden"}</div>;createVisibilityObserver takes a setter callback as the second argument. It is called when the element's intersection changes. The callback should return a boolean value indicating whether the element is visible — it'll be assigned to the signal.
const useVisibilityObserver = createVisibilityObserver({ threshold: 0.8 }, entry => {
// do some calculations on the intersection entry
return entry.isIntersecting;
});Exported modifiers
It provides information about element occurrence in the viewport — "Entering", "Leaving", "Inside" or "Outside".
import { createVisibilityObserver, withOccurrence } from "@solid-primitives/intersection-observer";
const useVisibilityObserver = createVisibilityObserver(
{ threshold: 0.8 },
withOccurrence((entry, { occurrence }) => {
console.log(occurrence); // => "Entering" | "Leaving" | "Inside" | "Outside"
return entry.isIntersecting;
}),
);It provides information about element direction on the screen — "Left", "Right", "Top", "Bottom" or "None".
import { createVisibilityObserver, withDirection } from "@solid-primitives/intersection-observer";
const useVisibilityObserver = createVisibilityObserver(
{ threshold: 0.8 },
withDirection((entry, { directionY, directionX, visible }) => {
if (!entry.isIntersecting && directionY === "Top" && visible) {
return true;
}
return entry.isIntersecting;
}),
);function createViewportObserver(
elements: MaybeAccessor<Element[]>,
callback: EntryCallback,
options?: IntersectionObserverInit,
): CreateViewportObserverReturnValue;See CHANGELOG.md