React hook for detecting element size changes using the native ResizeObserver API
npx @tessl/cli install tessl/npm-react-resize-detector@12.3.0React Resize Detector is a modern hook-based library that provides element size change detection using the native ResizeObserver API. It enables React applications to respond to element resizing without relying on window resize listeners or polling timeouts.
npm install react-resize-detectorimport { useResizeDetector } from "react-resize-detector";For CommonJS:
const { useResizeDetector } = require("react-resize-detector");Type imports:
import type {
UseResizeDetectorReturn,
useResizeDetectorProps,
OnResizeCallback,
ResizePayload,
RefreshModeType,
RefreshOptionsType,
Dimensions,
OnRefChangeType,
} from "react-resize-detector";Note:
OnRefChangeTypemay not be directly importable in some versions as it's not explicitly re-exported from the main index. It's used in theUseResizeDetectorReturninterface but may require TypeScript's type inference to access.
import { useResizeDetector } from "react-resize-detector";
const MyComponent = () => {
const { width, height, ref } = useResizeDetector<HTMLDivElement>();
return <div ref={ref}>{`${width}x${height}`}</div>;
};React Resize Detector is built around:
useResizeDetector hookThe main hook for detecting element resize events using ResizeObserver API.
/**
* React hook for detecting element resize events
* @param props - Configuration options for resize detection
* @returns Object containing dimensions and ref to attach to DOM element
*/
function useResizeDetector<T extends HTMLElement = HTMLElement>(
props?: useResizeDetectorProps<T>
): UseResizeDetectorReturn<T>;
interface useResizeDetectorProps<T extends HTMLElement> {
/** Callback invoked with resize information */
onResize?: OnResizeCallback;
/** Trigger updates on width changes (default: true) */
handleWidth?: boolean;
/** Trigger updates on height changes (default: true) */
handleHeight?: boolean;
/** Skip the first resize event when component mounts (default: false) */
skipOnMount?: boolean;
/** Disable re-renders triggered by the hook, only call onResize (default: false) */
disableRerender?: boolean;
/** Rate limiting strategy ('throttle' | 'debounce') */
refreshMode?: RefreshModeType;
/** Delay in milliseconds for rate limiting (default: 1000) */
refreshRate?: number;
/** Additional options for throttle/debounce */
refreshOptions?: RefreshOptionsType;
/** Options passed to ResizeObserver.observe() */
observerOptions?: ResizeObserverOptions;
/** External ref to observe (use with caution) */
targetRef?: React.MutableRefObject<T | null>;
}
interface UseResizeDetectorReturn<T> extends Dimensions {
/** Ref to attach to DOM element for resize observation */
ref: OnRefChangeType<T>;
}Usage Examples:
// Basic usage
const { width, height, ref } = useResizeDetector<HTMLDivElement>();
// With resize callback
const { width, height, ref } = useResizeDetector<HTMLDivElement>({
onResize: ({ width, height, entry }) => {
console.log('Resized to:', width, height);
}
});
// Performance optimized
const { width, ref } = useResizeDetector<HTMLDivElement>({
handleHeight: false, // Only track width
refreshMode: 'debounce',
refreshRate: 100,
observerOptions: { box: 'border-box' }
});
// External ref usage
import { useRef } from 'react';
const targetRef = useRef<HTMLDivElement>(null);
const { width, height } = useResizeDetector({ targetRef });Types for handling resize events and callbacks.
/**
* Callback function invoked when element is resized
* @param payload - Resize information containing dimensions and ResizeObserverEntry
*/
type OnResizeCallback = (payload: ResizePayload) => void;
/**
* Payload passed to onResize callback
* Contains element dimensions or null if element is unmounted
*/
type ResizePayload =
| { width: number; height: number; entry: ResizeObserverEntry }
| { width: null; height: null; entry: null };Types for configuring performance optimization through rate limiting.
/** Rate limiting strategy options */
type RefreshModeType = 'throttle' | 'debounce';
/** Additional options for throttle/debounce behavior */
type RefreshOptionsType = {
/** Execute on the leading edge of the delay (default: false for debounce, true for throttle) */
leading?: boolean;
/** Execute on the trailing edge of the delay (default: true) */
trailing?: boolean;
};Types for representing element dimensions.
/** Element dimension values */
type Dimensions = {
/** Element height in pixels */
height?: number;
/** Element width in pixels */
width?: number;
};
/**
* Ref callback function type with current property
* Can be called as function or accessed via .current property
*/
type OnRefChangeType<T> = {
(node: T | null): void;
current?: T | null;
};import { useResizeDetector } from "react-resize-detector";
const ResponsiveCard = () => {
const { width, ref } = useResizeDetector<HTMLDivElement>();
const cardStyle = {
padding: width && width > 600 ? '2rem' : '1rem',
fontSize: width && width > 400 ? '1.2em' : '1em',
flexDirection: width && width > 500 ? 'row' : 'column',
};
return (
<div ref={ref} style={cardStyle}>
<h2>Responsive Card</h2>
<p>Width: {width}px</p>
</div>
);
};import { useResizeDetector } from "react-resize-detector";
import { useCallback, useEffect, useRef } from "react";
const Chart = () => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const { width, height, ref } = useResizeDetector<HTMLCanvasElement>({
refreshMode: 'debounce',
refreshRate: 100,
});
// Merge refs to both track resize and access canvas element
const mergedRef = useCallback((node: HTMLCanvasElement | null) => {
canvasRef.current = node;
ref(node);
}, [ref]);
useEffect(() => {
if (width && height && canvasRef.current) {
// Redraw chart with new dimensions
redrawChart(canvasRef.current, width, height);
}
}, [width, height]);
return <canvas ref={mergedRef} />;
};import { useResizeDetector } from "react-resize-detector";
const OptimizedComponent = () => {
const { width, ref } = useResizeDetector<HTMLDivElement>({
// Only track width changes for better performance
handleHeight: false,
// Debounce rapid changes
refreshMode: 'debounce',
refreshRate: 150,
// Skip initial mount calculation
skipOnMount: true,
// Use border-box for more accurate measurements
observerOptions: { box: 'border-box' },
});
return <div ref={ref}>Optimized: {width}px wide</div>;
};import { useResizeDetector } from "react-resize-detector";
const NonRerenderingComponent = () => {
const { ref } = useResizeDetector<HTMLDivElement>({
// Disable re-renders triggered by the hook
disableRerender: true,
// Handle resize events through callback only
onResize: ({ width, height }) => {
// Update external state or perform side effects
// without causing component re-renders
console.log('Resized to:', width, height);
},
});
return <div ref={ref}>This component won't re-render on resize</div>;
};For older browsers, consider using a ResizeObserver polyfill.