Community JavaScript Snippet
useElementSize With ResizeObserver
Measuring a DOM node's width and height in React without listening to `window.resize`. Uses `ResizeObserver` so it fires for layout-driven changes (sidebar toggling, font load, parent flex) too.
useElementSize With ResizeObserver
Measuring a DOM node's width and height in React without listening to `window.resize`. Uses `ResizeObserver` so it fires for layout-driven changes (sidebar toggling, font load, parent flex) too.
By @lilykelly
April 7, 2026
·
Updated May 18, 2026
977 views
30
4.4 (8)
I always reach for a callback ref over useRef + useEffect for measurement hooks because the timing is cleaner: the callback runs synchronously when React attaches or detaches the node, so I never measure before mount or leak an observer after unmount. The Object.is check inside setSize keeps the state stable when the browser fires noisy ResizeObserver events with the same dimensions, which I have seen happen during scroll-into-view animations. Storing the observer in a ref lets me disconnect cleanly when the consumer swaps elements (a common pattern in conditional rendering).
When a sidebar collapses with a 300ms transition, ResizeObserver will fire on every layout pass. Bumping each event into React state means up to twenty re-renders per second on the consumer, often for invisible 0.5px deltas. Coalescing into requestAnimationFrame flips that to one render per frame, which is the rate the browser is going to paint anyway. The pattern is: stash the latest entry in a ref, schedule a single rAF if one is not pending, and clear the rAF on the next event so we always commit the freshest size. The fallback setTimeout(cb, 16) keeps it useful in non-DOM environments like Jest.
This is the whole point of using useElementSize: container queries before browsers had them. The card decides its layout from its OWN rendered width via the size returned by accordion 1's hook, then layoutFor() maps that width to a layout token. I use this so a sidebar that goes from 320px wide to 800px wide on a desktop drag rearranges itself without me wiring media-query hacks per breakpoint. Width 0 means "not yet measured", which I render as a skeleton or a default layout to avoid a flash of the wrong shape on first paint.
