iTranslated by AI
The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🖥️
[React] Custom Hook to Detect if an Element is Visible, Above, or Below the Viewport
In React, I created a custom hook (though I ended up not using it) to check whether a specific element currently falls into one of the following categories:
- Inside the screen (within the viewport)
- Above the screen
- Below the screen
I'm sharing it here as a small tribute. It uses the Intersection Observer API for better performance.
Creating the Custom Hook
useOnScreen.tsx
import React, { useState, useEffect } from 'react';
type TargetViewPosition = undefined | 'ABOVE_VIEWPORT' | 'BELOW_VIEWPORT' | 'VISIBLE';
export function useOnScreen(targetRef: React.RefObject<HTMLElement>) {
const [targetViewPosition, setTargetViewPosition] = useState<
TargetViewPosition
>(undefined);
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setTargetViewPosition('VISIBLE'); // Visible on screen
return;
}
if (entry.boundingClientRect.top > 0) {
setTargetViewPosition('BELOW_VIEWPORT'); // Positioned below the screen
} else {
setTargetViewPosition('ABOVE_VIEWPORT'); // Positioned above the screen
}
},
{
root: null,
threshold: 0,
}
);
useEffect(() => {
// Register the observer on mount
if (targetRef.current) observer.observe(targetRef.current);
// Disconnect the observer on unmount
return () => {
observer.disconnect();
};
}, []);
return targetViewPosition;
}
Usage
↓ Pass the ref of the element you want to track to the custom hook's argument.
SomeComponent.tsx
import { useOnScreen } from "./useOnScreen.tsx"
export const SomeComponent: React.VFC = () => {
const targetViewPosition = useOnScreen();
return (
<>
{targetViewPosition === 'VISIBLE' && <p>Visible on screen</p>}
{targetViewPosition === 'ABOVE_VIEWPORT' && <p>Positioned above the screen</p>}
{targetViewPosition === 'BELOW_VIEWPORT' && <p>Positioned below the screen</p>}
<div ref={targetRef}>Target element for position checking</div>
</>
)
}
There might not be many use cases for it, though.
Discussion