Skip to content

useVisible

Hook to know if an element is visible and optionally the visible area ration of the element.

Demo

INFO

The component renders a scrollable div with inside a bordered div element to which is attached _cbRef refCallback returned from useVisible hook. Component displays the bordered div visibility and ratio that change when parent div is scrolled.

Loading demo…
Show source code
tsx
import { useVisible } from "../../../..";

export const UseVisible = () => {
	const [cbRef, isVisible, ratio] = useVisible(
		{ mode: "ref" },
		{
			threshold: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1],
			withRatio: true
		}
	);
	return (
		<div>
			<div style={{ marginTop: 16, color: ratio === 1 ? '#98c379' : ratio === 0 ? '#e46962' : '#d2c04c' }}>
				<p>isVisible: {isVisible ? 'visible' : 'hidden'}</p>
				<p>ratio: {ratio}</p>
			</div>
			<div style={{ margin: 'auto', width: 300, height: 300, overflow: 'scroll', border: '1px solid' }}>
				<p>scrollable div</p>
				<div style={{ height: 800 }}>
					<div
						ref={cbRef}
						style={{
							border: '1px solid',
							margin: '320px auto 0px',
							height: 100,
							width: 100,
							textAlign: 'center',
						}}
					>
						bordered div
					</div>
				</div>
			</div>
		</div>
	);
}

Types

UseVisibleAttachOptions

  • @template T - The element type being observed.

Controls how the target element is attached to the {@link IntersectionObserver} used internally by useVisible.

ts
export type UseVisibleAttachOptions<T extends Element> =
	| {
		/**
		 * The hook returns a `RefCallback` to attach directly to the JSX element.
		 * The observer is connected when the ref is set and disconnected when the
		 * element is unmounted.
		 */
		mode: "ref";
		targetRef?: never;
	}
	| {
		/**
		 * - **`"effect"`** — The observer is connected inside a `useEffect` using
		 *   the provided `targetRef`, running asynchronously after the browser paints.
		 * - **`"layout-effect"`** — The observer is connected inside a
		 *   `useLayoutEffect` using the provided `targetRef`, running synchronously
		 *   before the browser paints.
		 */
		mode: "effect" | "layout-effect";

		/**
		 * A React `RefObject` pointing to the element to observe. Required when
		 * `mode` is `"effect"` or `"layout-effect"`.
		 */
		targetRef: RefObject<T>;
	};

UseVisibleOptions

Options accepted by useVisible. Extends {@link IntersectionObserverInit} with an additional withRatio flag.

ts
export type UseVisibleOptions = IntersectionObserverInit & {
	/**
	 * When `true`, the hook returns a third tuple entry containing the current
	 * intersection ratio as a `number` between `0` and `1`, where `0` means the
	 * element is fully outside the viewport and `1` means it is fully visible.
	 * When `false` or omitted, only the boolean visibility flag is returned.
	 */
	withRatio?: boolean;
};

UseVisibleResult

  • @template T - The element type being observed.

Return value of useVisible when withRatio is false, undefined, or opts is omitted entirely.

IndexTypeDescription
[0]RefCallback<T> \| nullA React ref callback to attach to the target element. Only populated when attachOptions.mode is "ref"null in "effect" and "layout-effect" modes where the target is provided via targetRef instead.
[1]booleanReactive boolean that is true when at least part of the target element intersects the viewport (or the configured root), and false otherwise.

UseVisibleWithRatioResult

  • @template T - The element type being observed.

Return value of useVisible when withRatio is true.

IndexTypeDescription
[0]RefCallback<T> \| nullA React ref callback to attach to the target element. Only populated when attachOptions.mode is "ref"null in "effect" and "layout-effect" modes where the target is provided via targetRef instead.
[1]booleanReactive boolean that is true when at least part of the target element intersects the viewport (or the configured root), and false otherwise.
[2]numberThe current intersection ratio as a number between 0 and 1. 0 means the element is fully outside the viewport; 1 means it is fully visible. Updated on every intersection change event.

Released under the MIT License.