mrkeyoor.com_
Tue 22 Sept 18:50 UTC
npmWeb Frontendupdated 22 Sept 2026

react-use-measure review

react-use-measure 2.1.7 is a React hook that watches one HTML or SVG element and returns its viewport rectangle: `x`, `y`, edges, width, and height. It combines `ResizeObserver` with window resize and orientation events, and can also listen to every scrollable ancestor when `scroll: true` is enabled. Options cover separate resize and scroll debounce times, an injected observer polyfill, and unscaled HTML offset dimensions. The current source returns a callback ref, frozen bounds, and `forceRefresh`; the README still shows a 2-item tuple and a mutable ref. Version 2.1.7 only removed testing install scripts, so there is no application API migration.

Verdict

react-use-measure 2.1.7 added 4.3 KB gzipped in our browser build and installed in 1.2 seconds with 0 audit findings, a reasonable cost when size and viewport position must update together. Use a narrower ResizeObserver hook when dimensions alone are enough, and plan for 0 values on the first render.

We installed it

Lab card: what happened when we installed react-use-measureScreenshot of react-use-measure documentation
Install✓ · 1.2s2 packages on disk · 1 MB
ImportESM import works · require() works · ESM package with exports map
Browser4.3 KBgzipped (11.4 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does react-use-measure install cleanly?

Yes. In a fresh container with an empty cache, npm install react-use-measure finished in 1 seconds, leaving 2 packages and 1 MB on disk. npm audit reported no known vulnerabilities.

How much does react-use-measure add to a browser bundle?

4.3 KB gzipped (11.4 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does react-use-measure work with both ESM and CommonJS?

Yes. Both import 'react-use-measure' and require('react-use-measure') worked in Node 22 in our run. The package is published as ESM with an exports map.

Does react-use-measure include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

react-use-measure or use-resize-observer: which should you use?

use-resize-observer: Use it when width and height are enough and rounding or observation-box options matter. react-use-measure 2.1.7 added 4.3 KB gzipped in our browser build and installed in 1.2 seconds with 0 audit findings, a reasonable cost when size and viewport position must update together.

When should you not use react-use-measure?

The first server or client render needs real dimensions. Every bound starts at 0 and changes only after the ref attaches and measurement runs.

API stability4/5The hook's ref-and-rectangle model remains small, and 2.1.7 made no application-facing API change while removing test install scripts from packaging. Options for scroll tracking, debounce, a polyfill, and offset size are additive. Confidence drops because the README shows a mutable ref and 2-item tuple while the published source and declarations return a callback ref, bounds, and a third `forceRefresh` function; types are the reliable contract here.
Docs3/5The README gets a developer to working code quickly and states the zero-value first render, observer requirement, nested-scroll behavior, options, polyfill injection, and callback-ref composition. It omits SSR timing, jsdom setup, orientation listeners, frozen results, and the exact limits of `offsetSize`. Its displayed return signature is also stale against 2.1.7 source, where the tuple has 3 items and the first is a callback ref.
Maintenance3/5Version 2.1.7 and the repository's latest push both date to January 30, 2025. The repository is not archived, has 984 stars, and GitHub search returns 17 open issues without pull requests. The last release removed test install scripts rather than changing behavior. A small hook can remain useful while quiet, but there has been no visible source push for about 19 months by August 2026, so React and browser regressions need local tests.
Ecosystem4/5The npm endpoint counted 6,656,057 downloads for August 18 through August 24, 2026. Our install found 0 runtime dependencies, bundled types, working CommonJS and ESM paths, and a 4.3 KB gzipped browser build. The hook accepts HTML and SVG nodes and emits ordinary rectangle numbers, so charts, animation systems, overlays, and canvases can consume it without adapters. React and ReactDOM remain the 2 required peers.

Use it if

  • An overlay, chart, canvas, or pointer interaction needs both element size and viewport coordinates.
  • The target can move inside nested scrolling containers and those scroll updates must trigger React state.
  • HTML and SVG elements should share one measurement hook, with zero initial values handled explicitly.
  • A transformed HTML element needs layout width and height from `offsetWidth` and `offsetHeight` via `offsetSize`.
Skip it if

Setup reality

We installed react-use-measure 2.1.7 in a fresh Node 22 Bookworm sandbox. npm finished in 1.2 seconds, left 2 packages using 1 MB, and reported 0 known vulnerabilities. The package has 0 direct dependencies and 2 peer dependencies, React and ReactDOM. It includes TypeScript declarations, uses ESM with an exports map, and worked through both require() and ESM import. Our browser import measured 11.4 KB minified and 4.3 KB gzipped; the package is 60 KB unpacked.

There are no credentials or config files. The hook can render during SSR because it substitutes an inert observer while window is missing, but server and first client values remain 0. Attach the callback ref to exactly one HTML or SVG node. If a local ref or animation library also needs the node, compose callback refs instead of replacing the measurement ref.

Modern browsers supply ResizeObserver; older test runners and browsers need an injected constructor such as @juggle/resize-observer. In jsdom, create a controllable stub and invoke its callback after changing getBoundingClientRect(). The source returns 3 tuple items in 2.1.7: the ref, frozen bounds, and forceRefresh, even though the README signature displays only the first 2.

Measurements are viewport-relative and include CSS transforms. offsetSize: true substitutes offsetWidth and offsetHeight for HTML size only. With scroll: true, the hook walks ancestors whose computed overflow is auto or scroll, installs passive capture listeners, and also watches window scroll. Debounce expensive consumers, accepting that delayed bounds can make an overlay visibly trail movement.

Patterns

Read a card rectangle after layout measure-bounds

import useMeasure from 'react-use-measure'

function Card() {
  const [measureRef, bounds] = useMeasure()
  return <section ref={measureRef}>{Math.round(bounds.width)} x {Math.round(bounds.height)}</section>
}

All 8 rectangle values start at 0. The callback ref and observer schedule a real measurement after the DOM node exists.

Render a chart from container width size-chart

const [ref, bounds] = useMeasure({ debounce: 50 })
return (
  <div ref={ref}>
    {bounds.width > 0 && <Chart width={bounds.width} height={Math.max(240, bounds.width / 2)} />}
  </div>
)

The width guard avoids rendering the chart at 0 pixels. A 50 ms debounce reduces chart rerenders but delays resize feedback.

Update coordinates during nested scroll track-scroll

const [ref, bounds] = useMeasure({
  scroll: true,
  debounce: { scroll: 8, resize: 80 },
})

`scroll: true` attaches passive capture listeners to every ancestor with `auto` or `scroll` overflow and to the window.

Supply ResizeObserver explicitly inject-observer

import { ResizeObserver } from '@juggle/resize-observer'
import useMeasure from 'react-use-measure'

const [ref, bounds] = useMeasure({ polyfill: ResizeObserver })

`@juggle/resize-observer` is a separate install. Version 2.1.7 throws in a browser that has no native or injected observer.

Use HTML layout dimensions ignore-scale-size

const [ref, bounds] = useMeasure({ offsetSize: true })
return <div style={{ transform: 'scale(.75)' }}><div ref={ref}>{bounds.width}</div></div>

`offsetSize` replaces width and height only for an `HTMLElement`. Coordinates and every SVG measurement still come from `getBoundingClientRect()`.

Share one node between callback refs merge-refs

import { mergeRefs } from 'react-merge-refs'

const localRef = useRef(null)
const [measureRef, bounds] = useMeasure()
return <div ref={mergeRefs([localRef, measureRef])}>{bounds.width}</div>

`react-merge-refs` is a separate package. Overwriting `measureRef` prevents react-use-measure from observing the node and cleaning listeners.

Measure after fonts settle force-refresh

const [ref, bounds, forceRefresh] = useMeasure()

useEffect(() => {
  document.fonts?.ready.then(forceRefresh)
}, [forceRefresh])

The third tuple item exists in 2.1.7 source and types but is absent from the README signature. ResizeObserver often makes it unnecessary.

Place a fixed panel below an anchor position-fixed-overlay

const [anchorRef, bounds] = useMeasure({ scroll: true })
return <>
  <button ref={anchorRef}>Details</button>
  <div style={{ position: 'fixed', top: bounds.bottom + 8, left: bounds.left }}>Panel</div>
</>

The bounds are viewport-relative, matching `position: fixed`. Collision handling, focus, portals, and clipping still need application or overlay-library logic.

Convert pointer coordinates to local space map-pointer

const [surfaceRef, bounds] = useMeasure({ scroll: true })
function onPointerMove(event) {
  updateCursor({ x: event.clientX - bounds.left, y: event.clientY - bounds.top })
}
return <div ref={surfaceRef} onPointerMove={onPointerMove} />

`clientX` and `clientY` share the viewport coordinate space of the measured left and top values. CSS scale may require another conversion.

Observe an SVG group measure-svg

const [groupRef, bounds] = useMeasure()
return <svg width="100%" height="240">
  <g ref={groupRef}><circle cx="80" cy="80" r="40" /></g>
  <text y="220">{bounds.width.toFixed(1)}</text>
</svg>

The callback ref accepts `SVGElement`. `offsetSize` has no effect because SVG nodes lack `offsetWidth` and `offsetHeight`.

Wait before showing geometry controls avoid-hydration-branch

const [ref, bounds] = useMeasure()
const ready = bounds.width > 0 || bounds.height > 0
return <div ref={ref}><Content />{ready && <GeometryControls bounds={bounds} />}</div>

SSR and the first client render both see 0 values. Keeping their initial markup stable avoids a geometry-driven hydration mismatch.

Tune resize and scroll separately debounce-events

const [ref, bounds] = useMeasure({
  scroll: true,
  debounce: { scroll: 16, resize: 120 },
})

A 16 ms scroll delay tracks motion more closely than the 120 ms resize delay, but both leave bounds stale until their timers fire.

Alternatives

PackageRegistryPick it when
use-resize-observernpmUse it when width and height are enough and rounding or observation-box options matter.
react-resize-detectornpmUse it when you prefer a hook or component API with explicit refresh controls.
@react-hook/resize-observernpmUse it for a narrow ResizeObserver wrapper when position tracking belongs elsewhere.

More web frontend guides

postcss · react · react-dom · tailwindcss · htmlparser2 · tailwind-merge · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.