react-use-measure
A tiny React hook that reactively measures an element's bounding box on resize, scroll, and orientation change.
Repository Health
Technical Analysis
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 manualforceRefreshfunction - Automatic re-measurement via
ResizeObserverwhenever 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
offsetSizeoption to measure usingoffsetWidth/offsetHeightso parent CSS transforms don’t skew the reported size - Pluggable
ResizeObserverpolyfill 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.
Used by 4 apps in this directory
ILLA Builder
Developer Tools · Low Code Platforms · No Code Platforms
Open-source low-code platform for building internal tools with drag-and-drop UI, reactive data bindings, and real-time collaboration.
Outline
Knowledge Management · Collaboration
A fast, real-time collaborative knowledge base for growing teams built on React, Node.js, and ProseMirror.
Pezzo
AI Development · Monitoring
Open-source LLMOps platform for prompt management, AI observability, intelligent caching, and real-time cost tracking across LLM providers.
Umami
Analytics
Privacy-first web analytics that respects your users — self-hosted, cookieless, and GDPR compliant out of the box.