React hook utility for measuring DOM element boundaries with reactive updates
npx @tessl/cli install tessl/npm-react-use-measure@2.1.0React Use Measure is a utility React hook for measuring DOM element boundaries with reactive updates. It provides precise position and size information that accounts for scroll containers and viewport changes, solving the common problem of getting accurate element positioning in dynamic React applications.
npm install react-use-measureimport useMeasure from "react-use-measure";
import type { RectReadOnly, Options } from "react-use-measure";For CommonJS:
const useMeasure = require("react-use-measure");
// For accessing the default export specifically:
// const useMeasure = require("react-use-measure").default;import React from "react";
import useMeasure from "react-use-measure";
function MyComponent() {
const [ref, bounds] = useMeasure();
return (
<div>
<div ref={ref}>
Measure me!
</div>
<p>
Size: {bounds.width}x{bounds.height}
Position: ({bounds.left}, {bounds.top})
</p>
</div>
);
}React Use Measure is built around several key components:
The primary useMeasure hook provides DOM element measurement with reactive updates.
/**
* React hook for measuring DOM element boundaries with reactive updates
* @param options - Configuration options for measurement behavior (defaults: { debounce: 0, scroll: false, offsetSize: false })
* @returns Tuple containing ref callback, bounds object, and force refresh function
*/
function useMeasure(options?: Options): [
(element: HTMLOrSVGElement | null) => void,
RectReadOnly,
() => void
];Usage Example:
import useMeasure from "react-use-measure";
function ResponsiveComponent() {
const [ref, bounds, forceRefresh] = useMeasure({
debounce: 100,
scroll: true
});
// Use forceRefresh to manually trigger measurement
const handleRefresh = () => {
forceRefresh();
};
return (
<div>
<div ref={ref}>Content to measure</div>
<button onClick={handleRefresh}>Force Refresh</button>
</div>
);
}Configure measurement behavior with debouncing, scroll tracking, and polyfill support.
interface Options {
/** Debounce events in milliseconds or separate values for scroll/resize (default: 0) */
debounce?: number | { scroll: number; resize: number };
/** React to nested scroll changes - use with caution for performance (default: false) */
scroll?: boolean;
/** Inject a ResizeObserver polyfill for browser compatibility */
polyfill?: { new (cb: ResizeObserverCallback): ResizeObserver };
/** Use offsetWidth/offsetHeight instead of getBoundingClientRect for sizing (default: false) */
offsetSize?: boolean;
}Usage Example:
import useMeasure from "react-use-measure";
import { ResizeObserver } from "@juggle/resize-observer";
function AdvancedComponent() {
const [ref, bounds] = useMeasure({
debounce: { scroll: 50, resize: 100 },
scroll: true,
polyfill: ResizeObserver,
offsetSize: true
});
return <div ref={ref}>Advanced measurement</div>;
}Enable scroll tracking to get accurate positioning within scroll containers.
// Enable scroll tracking for elements within scrollable containers
const [ref, bounds] = useMeasure({ scroll: true });
// With scroll tracking, bounds.top and bounds.left account for:
// - Page scroll position
// - Nested scroll container positions
// - Viewport changesControl performance with debouncing options for scroll and resize events.
// Simple debouncing - same value for both scroll and resize
const [ref, bounds] = useMeasure({ debounce: 100 });
// Separate debouncing for scroll vs resize events
const [ref, bounds] = useMeasure({
debounce: { scroll: 50, resize: 200 }
});
// No debouncing for immediate updates
const [ref, bounds] = useMeasure({ debounce: 0 });interface RectReadOnly {
/** X coordinate relative to viewport */
readonly x: number;
/** Y coordinate relative to viewport */
readonly y: number;
/** Element width in pixels */
readonly width: number;
/** Element height in pixels */
readonly height: number;
/** Distance from top edge of viewport */
readonly top: number;
/** Distance from right edge of viewport */
readonly right: number;
/** Distance from bottom edge of viewport */
readonly bottom: number;
/** Distance from left edge of viewport */
readonly left: number;
/** Index signature for additional numeric properties */
[key: string]: number;
}/** The return type of the useMeasure hook */
type UseMeasureResult = [
/** Ref callback to attach to the element you want to measure */
(element: HTMLOrSVGElement | null) => void,
/** Current bounds/measurements of the element */
RectReadOnly,
/** Function to manually trigger a measurement update */
() => void
];/** Union type for HTML and SVG elements that can be measured */
type HTMLOrSVGElement = HTMLElement | SVGElement;/** ResizeObserver callback function type */
type ResizeObserverCallback = (entries: any[], observer: ResizeObserver) => void;
/** ResizeObserver class declaration for polyfill compatibility */
declare class ResizeObserver {
constructor(callback: ResizeObserverCallback);
observe(target: Element, options?: any): void;
unobserve(target: Element): void;
disconnect(): void;
static toString(): string;
}The hook throws a descriptive error when ResizeObserver is not available:
// This will throw if ResizeObserver is not supported and no polyfill is provided
const [ref, bounds] = useMeasure();
// Error message: "This browser does not support ResizeObserver out of the box.
// See: https://github.com/react-spring/react-use-measure/#resize-observer-polyfills"
// Solution: Provide a polyfill
import { ResizeObserver } from "@juggle/resize-observer";
const [ref, bounds] = useMeasure({ polyfill: ResizeObserver });