ResizeObserver watches element size changes — not the viewport. This enables truly responsive components.
Basic Usage
const observer = new ResizeObserver((entries) => {
for (const entry of entries) {
const { width, height } = entry.contentRect;
console.log(`Element resized: ${width}x${height}`);
// Apply responsive classes based on element size
if (width < 300) {
entry.target.classList.add("compact");
} else {
entry.target.classList.remove("compact");
}
}
});
observer.observe(document.querySelector(".card"));React Hook
function useResizeObserver(ref) {
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
useEffect(() => {
if (!ref.current) return;
const observer = new ResizeObserver((entries) => {
const { width, height } = entries[0].contentRect;
setDimensions({ width, height });
});
observer.observe(ref.current);
return () => observer.disconnect();
}, [ref]);
return dimensions;
}
// Usage
function ResponsiveCard() {
const ref = useRef(null);
const { width } = useResizeObserver(ref);
return (
<div ref={ref} className={width < 400 ? "card-compact" : "card-full"}>
{width < 400 ? <CompactView /> : <FullView />}
</div>
);
}Use Cases
1. Responsive Charts
function ResponsiveChart({ data }) {
const containerRef = useRef();
const { width, height } = useResizeObserver(containerRef);
return (
<div ref={containerRef} style={{ width: "100%", height: "400px" }}>
<Chart data={data} width={width} height={height} />
</div>
);
}2. Text Truncation
function TruncatedText({ text }) {
const ref = useRef();
const { width } = useResizeObserver(ref);
const maxChars = Math.floor(width / 8); // Rough estimate
return (
<div ref={ref}>
{text.length > maxChars ? text.slice(0, maxChars) + "..." : text}
</div>
);
}3. Dynamic Grid Columns
function AutoGrid({ children, minColumnWidth = 250 }) {
const ref = useRef();
const { width } = useResizeObserver(ref);
const columns = Math.max(1, Math.floor(width / minColumnWidth));
return (
<div
ref={ref}
style={{
display: "grid",
gridTemplateColumns: `repeat(${columns}, 1fr)`,
gap: "16px"
}}
>
{children}
</div>
);
}Performance Tips
- ResizeObserver callbacks are debounced by the browser (after layout, before paint)
- Avoid layout changes inside the callback that trigger more resizes (infinite loop risk)
- Use a single observer instance for multiple elements when possible
- Disconnect when component unmounts