30% offEnding soon
useElementBoundingLoading saved progress…

useElementBounding

useElementBounding is a React hook that tracks an element's size and its position in the viewport as a live { width, height, top, left, right, bottom, x, y } object, re-measuring whenever the page scrolls, the window resizes, or the element itself changes size. It is the reactive wrapper around getBoundingClientRect: you attach a ref, and the hook keeps a fresh measurement in state.

You reach for it to anchor a tooltip or popover to its trigger, draw a highlight box over a target, or position a floating menu — anything that needs to know where an element is on screen right now, not just how big it is. VueUse ships this hook under the same name; you are building the React equivalent.

Signature

// `ref` is a React ref you attach to the element you want to measure.
function useElementBounding(ref) {
  // returns a live object that re-measures on scroll, resize, and size changes:
  // { width, height, top, left, right, bottom, x, y }
}

Examples

function Box() {
  const ref = useRef(null);
  const rect = useElementBounding(ref);
  return <div ref={ref}>{rect.width} wide, top at {rect.top}px</div>;
}
// getBoundingClientRect is VIEWPORT-relative. Take an element sitting 300px
// down the page, with the page scrolled to the very top:
//   { top: 300, left: 0, ... }
// Now scroll the page down 200px. The element has NOT moved in the document,
// but its reported position has:
//   { top: 100, left: 0, ... }   // top fell by the 200px you scrolled

Notes

  • Position is viewport-relative. top, left, x, y, right, and bottom all come from getBoundingClientRect, so they change on every scroll — of the window or any scrollable ancestor — even though the element's place in the document has not changed.
  • Size and position are different signals. A ResizeObserver fires when the element's box changes size but never when the page scrolls. Keeping position fresh needs its own scroll and resize listeners.
  • Clean up on unmount. Every listener and observer you add has to be removed when the component unmounts, or each mount leaks another handler.
  • Numbers can be fractional and negative. getBoundingClientRect reports sub-pixel values, and an element scrolled above the top of the viewport has a negative top. Do not round or clamp them.
  • Assume one stable element. Don't worry about server rendering or the ref pointing at a different node over the component's life.