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