← Back to all hooks

useResizeObserver

Track element size changes using the ResizeObserver API. Perfect for responsive components and dynamic layouts.

Approach 1: Single Element

Track one element's dimensions. Simple and straightforward.

Drag the bottom-right corner to resize the box

Resizable Box

Width: 0px

Height: 0px

Area: 0 px²

Approach 2: Multiple Elements

Track multiple elements with a single observer. More efficient for many elements.

Single Observer tracking multiple elements

Drag corners to resize each box independently

Box 1

0 × 0px

Box 2

0 × 0px

Box 3

0 × 0px

Code Examples

Single Element

import { useResizeObserver } from "@uiblock/hooks";

export default function Demo() {
  const [ref, size] = useResizeObserver();

  return (
    <div ref={ref} style={{ resize: 'both', overflow: 'auto' }}>
      <p>Width: {size.width}px</p>
      <p>Height: {size.height}px</p>
    </div>
  );
}

Multiple Elements

import { useResizeObserverMultiple } from "@uiblock/hooks";
import { useRef, useEffect } from "react";

export default function Demo() {
  const { observe, getSize } = useResizeObserverMultiple();
  const box1Ref = useRef(null);
  const box2Ref = useRef(null);

  useEffect(() => {
    if (box1Ref.current) observe(box1Ref.current, 'box1');
    if (box2Ref.current) observe(box2Ref.current, 'box2');
  }, [observe]);

  const size1 = getSize('box1');
  const size2 = getSize('box2');

  return (
    <div>
      <div ref={box1Ref}>Box 1: {size1.width}x{size1.height}</div>
      <div ref={box2Ref}>Box 2: {size2.width}x{size2.height}</div>
    </div>
  );
}

When to Use Each

Single Element

  • One or few elements
  • Simple use cases
  • Independent tracking
  • Easier to understand

Multiple Elements

  • Many elements (10+)
  • Better performance
  • Grid/list layouts
  • Lower memory usage

How It Works

Here's the implementation:

import { useEffect, useRef, useState } from 'react'

export function useResizeObserver() {
  const [size, setSize] = useState({ width: 0, height: 0 })
  const ref = useRef(null)

  useEffect(() => {
    const element = ref.current
    if (!element) return

    const observer = new ResizeObserver((entries) => {
      const entry = entries[0]
      if (entry) {
        setSize({
          width: entry.contentRect.width,
          height: entry.contentRect.height
        })
      }
    })

    observer.observe(element)

    return () => observer.disconnect()
  }, [])

  return [ref, size]
}

Multiple Elements Version

For tracking multiple elements with a single observer:

import { useEffect, useRef, useState, useCallback } from 'react'

export function useResizeObserverMultiple() {
  const [sizeMap, setSizeMap] = useState(new Map())
  const observerRef = useRef(null)

  useEffect(() => {
    observerRef.current = new ResizeObserver((entries) => {
      setSizeMap((prev) => {
        const newMap = new Map(prev)
        entries.forEach((entry) => {
          const id = entry.target.getAttribute('data-resize-id')
          if (id) {
            newMap.set(id, {
              width: entry.contentRect.width,
              height: entry.contentRect.height
            })
          }
        })
        return newMap
      })
    })

    return () => observerRef.current?.disconnect()
  }, [])

  const observe = useCallback((element, id) => {
    if (!element || !observerRef.current) return

    element.setAttribute('data-resize-id', id)
    observerRef.current.observe(element)
  }, [])

  const getSize = useCallback(
    (id) => sizeMap.get(id) ?? { width: 0, height: 0 },
    [sizeMap]
  )

  return { observe, getSize, sizeMap }
}

API Reference

useResizeObserver

Parameters

None

Returns

[ref, size] - Ref to attach to element and size object with width and height

useResizeObserverMultiple

Parameters

None

Returns

observe(element, id) - Function to observe an element with a unique ID

getSize(id) - Function to get size of element with ID

sizeMap - Map of all element IDs and their sizes

💡 Use Cases

  • Responsive components that adapt to container size
  • Charts and visualizations that need to redraw on resize
  • Dynamic grid layouts
  • Text truncation based on available space
  • Container queries alternative