Skip to content

Instantly share code, notes, and snippets.

@rendro
Last active March 25, 2025 00:03
Show Gist options
  • Save rendro/a0e6299c04b15d847fffea1ff23cd87d to your computer and use it in GitHub Desktop.
Save rendro/a0e6299c04b15d847fffea1ff23cd87d to your computer and use it in GitHub Desktop.
Viewport Observer React Component
import { Slot } from "@radix-ui/react-slot";
type Props = React.ComponentPropsWithoutRef<"div"> & {
asChild?: boolean;
options?: IntersectionObserverInit;
onAppear?: () => void;
onDisappear?: () => void;
};
export function ViewportObserver({
asChild = false,
options,
onAppear,
onDisappear,
...props
}: Props) {
const Comp = asChild ? Slot : "div";
const handleIntersect: IntersectionObserverCallback = (entries) => {
const entry = entries.length > 0 ? entries[0]! : undefined;
if (entry !== undefined) {
if (entry.isIntersecting) {
onAppear?.();
} else {
onDisappear?.();
}
}
};
const observer = React.useRef(new IntersectionObserver(handleIntersect, options));
const ref = (el: HTMLDivElement | null) => {
if (el) {
observer.current.observe(el);
return () => observer.current.unobserve(el);
}
};
return <Comp ref={ref} {...props} />;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment