useIntersectionObserver
A React hook for observing when an element enters or exits the viewport using the Intersection Observer API.
- Installation
- Add Source Code
npm install @plenty-hooks/use-intersection-observer
npx @plenty-hooks/cli use-intersection-observer
Using this command will add the source code of the hook directly to your project.
Options:
--pathor-p: Specify the directory where the hook file should be saved--kebab-caseor-k: Use kebab-case for the output filename (e.g.,use-document-title.ts). By default, the filename uses camelCase (e.g.,useDocumentTitle.ts)
Note: By adding the source code of the hook directly to your project, you won't be able to install further updates automatically. You are on your own for maintaining and updating the code.
Showcase
import { useRef } from 'react';
import { useIntersectionObserver } from '@plenty-hooks/use-intersection-observer';
function LazyImage({ src, alt }: { src: string; alt: string }) {
const ref = useRef<HTMLDivElement>(null);
const [isVisible, setIsVisible] = useState(false);
useIntersectionObserver(
ref,
() => {
setIsVisible(true);
},
{ once: true }
);
return (
<div ref={ref}>
{isVisible ? <img src={src} alt={alt} /> : <div>Loading...</div>}
</div>
);
}
Triggering on Exit
You can configure the hook to trigger when an element exits the viewport:
import { useRef } from 'react';
import { useIntersectionObserver } from '@plenty-hooks/use-intersection-observer';
function TrackVisibility() {
const ref = useRef<HTMLDivElement>(null);
useIntersectionObserver(
ref,
(entry) => {
console.log('Element exited viewport');
},
{ trigger: 'exit' }
);
return <div ref={ref}>Track when I leave the viewport</div>;
}
Triggering on Both Enter and Exit
import { useRef } from 'react';
import { useIntersectionObserver } from '@plenty-hooks/use-intersection-observer';
function TrackBoth() {
const ref = useRef<HTMLDivElement>(null);
useIntersectionObserver(
ref,
(entry) => {
if (entry.isIntersecting) {
console.log('Entered viewport');
} else {
console.log('Exited viewport');
}
},
{ trigger: 'both' }
);
return <div ref={ref}>Track enter and exit</div>;
}
Global Configuration
Configure default options globally for all instances:
import { configUseIntersectionObserver } from '@plenty-hooks/use-intersection-observer';
// Configure once in your app entry point
configUseIntersectionObserver({
threshold: 0.5,
rootMargin: '10px',
});
API
useIntersectionObserver(ref, callback, options?)
Observes when an element enters or exits the viewport.
Parameters
ref: RefObject<T | null>- Ref to the element to observecallback: (entry: IntersectionObserverEntry) => void- Callback to fire when the element intersectsoptions(optional): Configuration object with the following properties:once?: boolean- If true, the callback will only be fired once (default:false)enable?: boolean- If false, the observer will not be created (default:true)rootTarget?: RefObject<Element | null> | Element | Document | null- The root element for the intersection observertrigger?: 'enter' | 'exit' | 'both'- When to trigger the callback (default:'enter')rootMargin?: string- Margin around the root (e.g.,'10px','10px 20px')threshold?: number | number[]- Threshold(s) at which to trigger callback (e.g.,0.5,[0, 0.5, 1])
Returns
void
configUseIntersectionObserver(options: Options)
Configures global default options for all useIntersectionObserver instances.
Parameters
options: Configuration object with the following properties:once?: boolean- If true, the callback will only be fired once (default:false)enable?: boolean- If false, the observer will not be created (default:true)rootTarget?: RefObject<Element | null> | Element | Document | null- The root element for the intersection observertrigger?: 'enter' | 'exit' | 'both'- When to trigger the callback (default:'enter')rootMargin?: string- Margin around the rootthreshold?: number | number[]- Threshold(s) at which to trigger callback
Types
interface Options {
once?: boolean;
enable?: boolean;
rootTarget?: RefObject<Element | null> | IntersectionObserverInit['root'];
trigger?: 'enter' | 'exit' | 'both';
rootMargin?: IntersectionObserverInit['rootMargin'];
threshold?: IntersectionObserverInit['threshold'];
}