react-use-measure

A tiny React hook that reactively measures an element's bounding box on resize, scroll, and orientation change.

Library
npm
v2.1.7
985stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
42/100Fair
Development Activity0
Maintenance20
Community48
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
77/100Good
Architecture82
Code Quality78
Innovation62
Learning Curve85

react-use-measure solves a problem that getBoundingClientRect alone can’t: knowing an element’s true position and size relative to the viewport when nested scroll containers, page scroll, or window resizing are involved. It exposes a single hook, useMeasure, that returns a ref callback and a read-only bounds object (x, y, width, height, top, right, bottom, left), keeping the values in sync as the DOM changes.

Under the hood it wires up a ResizeObserver on the measured element plus scroll listeners on every ancestor scroll container it can find, so layout-affecting changes anywhere in the ancestor chain trigger a re-measurement. It’s a maintained fork of the original react-use-measure lineage used widely across the pmndrs/react-spring ecosystem (react-three-fiber, use-gesture demos, and similar) wherever a component needs to know its own rendered size before it can lay out children or run physics-based animations.

What You Get

  • A single useMeasure() hook returning a ref callback, a read-only bounds object, and a manual forceRefresh function
  • Automatic re-measurement via ResizeObserver whenever the element’s size changes
  • Optional scroll tracking across nested scrollable ancestors, not just window scroll
  • Debounce configuration (a single number or separate scroll/resize values) to throttle rapid updates
  • An offsetSize option to measure using offsetWidth/offsetHeight so parent CSS transforms don’t skew the reported size
  • Pluggable ResizeObserver polyfill support for older browser targets

Common Use Cases

  • Measuring a container before rendering charts, canvases, or WebGL scenes that need pixel-accurate dimensions
  • Driving physics-based or size-dependent animations (e.g. react-spring) that need to know an element’s live bounds
  • Building responsive components that change layout based on their own measured width rather than a media query
  • Positioning tooltips, popovers, or overlays relative to a target element’s actual on-screen bounds
  • Detecting when an element scrolls into a different position inside a scrollable panel

Under The Hood

Architecture The entire library is a single file, src/index.ts, exporting one function: useMeasure. Internally it keeps a mutable state ref (element, scroll containers, resize observer, last bounds, orientation handler) so that update logic can run inside event callbacks without triggering extra renders, and only calls React’s setState when the freshly computed bounds actually differ from the last-known ones (areBoundsEqual). The returned ref callback both attaches the DOM node and, on each new node, tears down and rebuilds the resize observer plus the list of scrollable ancestor elements found by walking up parentElement and checking computed overflow/overflowX/overflowY. This callback-ref-plus-mutable-state pattern is the whole design: no external state library, no context, and no re-render unless bounds change.

Tech Stack Written in TypeScript, targeting react/react-dom as peer dependencies (>=16.13, with react-dom marked optional for non-DOM renderers). It has zero runtime dependencies of its own, relying entirely on the browser’s native ResizeObserver and screen.orientation/orientationchange APIs, with an optional polyfill injection point for environments lacking ResizeObserver. The package builds with Vite (vite build plus a tsc pass for declaration files) into dual ESM/CJS output (dist/index.js / dist/index.cjs) declared via a modern exports map, and ships both dist/* and src/* in its published files.

Code Quality Tests live in tests/index.test.tsx and are run with Vitest’s browser mode (@vitest/browser + Playwright), rendering real components with @testing-library/react and asserting on actual getBoundingClientRect output rather than mocks — including scenarios for switching refs, resizing, scaling, and injecting a resize-observer-polyfill. The source itself is compact and typed throughout (a RectReadOnly interface, a typed Options type, an internal State type), with no any beyond the necessary escape hatches for browser globals not present in all environments (e.g. ResizeObserver, screen.orientation). There’s no separate lint config beyond a .prettierrc, and no CI workflow visible beyond a .github directory placeholder.

What Makes It Unique Unlike most “element size” hooks that only watch the target element itself, this one also tracks every scrollable ancestor’s scroll events and native orientation-change events, so a component nested three scroll containers deep still gets accurate live bounds. It intentionally returns a plain, frozen, read-only bounds object rather than a class instance or proxy, keeping the API surface trivial to consume and easy to spread into other hooks.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search