An element-level resize observer
ResizeObserver notifies you when an observed element changes size. Before this API existed, the only size-related event available was resize on the document, which fires when the viewport changes. To react to a viewport resize, you had to attach that listener, then manually determine which elements were affected by querying getBoundingClientRect() or getComputedStyle() — operations that can cause layout thrashing if reads and writes aren't carefully batched.
That approach also missed many cases where elements change size without any viewport change: appending children, toggling display to none, or similar style changes can resize an element, its siblings, or its ancestors. ResizeObserver catches all of these, regardless of trigger, and supplies the new dimensions of the observed elements.
Browser support for ResizeObserver is available in all major engines:
- Chrome 64+
- Edge 79+
- Firefox 69+
- Safari 13.1+
How the API works
The API follows the same pattern as other Observer interfaces. You create a ResizeObserver instance with a callback; the callback receives an array of ResizeObserverEntry objects, one per observed element, each reporting the element's new dimensions.
const observer = new ResizeObserver(entries => {
for (const entry of entries) {
// Use entry.contentRect or the box size properties
}
});
observer.observe(targetElement);
Understanding the reported data
By default, a ResizeObserverEntry reports the element's content box via the contentRect property, which returns a DOMRectReadOnly. The content box is the border box minus padding — the area where content is placed. Note that the observer watches only the contentRect, even though padding dimensions are also reported. Don't confuse contentRect with the bounding box from getBoundingClientRect(), which includes the whole element and its descendants. SVG elements are the exception: for those, ResizeObserver reports the bounding box.
Chrome 84 added three properties to ResizeObserverEntry that provide more granular data. Each returns a ResizeObserverSize object with a blockSize and inlineSize, captured when the callback runs:
borderBoxSizecontentBoxSizedevicePixelContentBoxSize
All of these are arrays. They're read-only now because future versions may support elements with multiple fragments—which occur in multi-column layouts—so for the time being each array contains a single element. Firefox already supports borderBoxSize and contentBoxSize.
Timing and a callback gotcha
The specification requires ResizeObserver to deliver all resize events after layout but before paint. This makes the callback the ideal place to adjust page layout: changes made there only invalidate layout, not painting.
If you change the size of an observed element inside the callback, you will trigger another callback invocation. ResizeObserver avoids infinite loops and cyclic dependencies by applying a rule: a resize is only processed in the current frame if the resized element is deeper in the DOM than the shallowest element processed in the previous callback. Otherwise, the change is deferred to the next frame.
Practical applications
The API enables per-element design logic. You can observe an element and imperatively change its styles based on its own width, effectively emulating media queries at the element level — for example, adjusting a box's border radius when it narrows.
A chat window is another strong use case. Keeping the view scrolled to the newest messages requires reacting both to viewport size changes and to new messages being appended. ResizeObserver handles both with one piece of code: calling appendChild() resizes the container (unless overflow: hidden is set), which the observer detects and can respond to by resetting the scroll position to the bottom. The same observer also fires when the window resizes, so orientation changes are covered without additional listeners.
Custom elements that manage their own layout also benefit. Before ResizeObserver, there was no reliable way to be notified when a custom element's dimensions changed so its children could be re-laid out.
Impact on Interaction to Next Paint
ResizeObserver callbacks run just before rendering work, which means their execution time is counted toward rendering, and anything they change will likely require a visual update. This matters for Interaction to Next Paint (INP), a metric measuring page responsiveness. An INP of 200 milliseconds or less is considered good.
Because the callback delays rendering, you should keep the work there minimal. Recommended practices include:
- Using simple CSS selectors to avoid excessive style recalculations, which happen before layout.
- Avoiding any operations in the callback that trigger forced reflows.
- Keeping in mind that time spent updating layout grows as the DOM grows; for structurally complex pages, the cost of heavy
ResizeObservercallbacks becomes more pronounced.
Final considerations
ResizeObserver gives you efficient, element-scoped size monitoring in all major browsers. Used carefully—with minimal work in the callback—it lets you react to size changes precisely and promptly without blocking rendering.



