In this snippet we will look for the ResizeObserver API in javascript and what it does and how to observe specific element when a re-size is happened.
The Javascript ResizeObserver interface allows to execute specific logic when an element’s size changes, by observing this element.
One question, why we use the ResizeObserver and we can achieve similar things using CSS Responsive Design using media queries, but with the ResizeObserver we can do more than just changing CSS properties.
Basic Usage:
const resizeObserver = new ResizeObserver((entries) => {
});
resizeObserver.observe(element);
To start monitoring an element size change, we declare a new instance of the ResizeObserver which accepts a callback, that takes a single parameter entries. Inside the callback where we will write the logic to access the element’s new size.
Next we start observing using the created observer instance observe() method.
A simple example:
<style>
.box {
width: 500px;
height: 300px;
background: red;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
const box = document.querySelector('.box');
const observer = new ResizeObserver(entries => {
console.log('entries', entries);
for (const entry of entries)
{
console.log('Width:', entry.contentRect.width);
console.log('Height:', entry.contentRect.height);
}
});
observer.observe(box);
</script>
In this example we have a div with class=”box”. Whenever .box changes size, the callback is executed logging the Width and Height of the div in browser devTools.
If you checked the entries argument passed to the callback:
[ResizeObserverEntry]
0: ResizeObserverEntry
borderBoxSize:
[ResizeObserverSize]
contentBoxSize:
[ResizeObserverSize]
contentRect:
DOMRectReadOnly {x: 0, y: 0, width: 500, height: 300, top: 0, …}
devicePixelContentBoxSize:
[ResizeObserverSize]
target : div.box
Each entry is is an instance of ResizeObserverEntry interface which allows to access the new dimensions of the element. As you the ResizeObserverEntry have these properties:
borderBoxSize: An array of objects containing the new border box size of the observed element.contentBoxSize: An array of objects containing the new context box size of the observed element.contentRect: Which we used above, this is legacy property, meaning it may deprecate in the future, so instead depend on using thecontentBoxSizeproperty.
The borderBoxSize and contentBoxSize properties related to javascript box model specification of the element. When inspecting each of these properties, you will find it have two properties: the blockSize and inlineSize.
blockSize-
The length of the observed element’s content box in the block dimension. For boxes with a horizontal
writing-mode, this is the vertical dimension, or height; if the writing-mode is vertical, this is the horizontal dimension, or width.inlineSize-
The length of the observed element’s content box in the inline dimension. For boxes with a horizontal
writing-mode, this is the horizontal dimension, or width; if the writing-mode is vertical, this is the vertical dimension, or height.
Why Do We Need ResizeObserver?
Consider a dashboard containing a sidebar and a main content area.
<div class="dashboard">
<aside class="sidebar"></aside>
<main class="content"> ... </main>
</div>
Suppose the sidebar can be collapsed.
When the sidebar changes from: 250px → 70px
the content area also changes size.
The viewport could remain: 1440px × 900px. While the .content element changes from:
1190px → 1370px
A window.resize listener cannot reliably detect that change.
However ResizeObserver can:
const content = document.querySelector('.content');
const observer = new ResizeObserver(entries => {
const entry = entries[0];
if(entry.contentBoxSize) {
console.log( 'Content width:', entry.contextBoxSize[0].inlineSize );
} else {
console.log( 'Content width:', entry.contentRect.width );
}
});
observer.observe(content);
Notice how is this example to make it work with all browsers, i checked against the contentBoxSize property, if it exists then we use it and access the inlineSize property to get the element width, otherwise we used the legacy entry.contentRect.
Observing Multiple Elements
A single ResizeObserver can observe multiple elements.
const observer = new ResizeObserver(entries => {
for (const entry of entries)
{
if(entry.contentBoxSize) {
console.log('Width:', entry.contentBoxSize[0].inlineSize);
console.log('Height:', entry.contentBoxSize[0].blockSize);
} else {
console.log('Width:', entry.contentRect.width);
console.log('Height:', entry.contentRect.height);
}
}
});
observer.observe(document.querySelector('.box-1'));
observer.observe(document.querySelector('.box-2'));
observer.observe(document.querySelector('.box-3'));
The callback receives an entry for each element whose size changed. This is often preferable to creating a separate observer for every element.
Identifying the Element That Changed
The target property tells us which element the entry belongs to:
const observer = new ResizeObserver(entries => {
for (const entry of entries) {
console.log('Changed element:', entry.target);
}
});
This becomes particularly useful when observing a collection of components.
ResizeObserver vs window.resize
One of the most important things to understand is that these APIs solve different problems.
window.resize
window.addEventListener('resize', () => {
console.log('Viewport changed');
});
This is useful when you care about changes to the browser viewport.
For example:
window.addEventListener('resize', () => {
if (window.innerWidth < 768) {
// Mobile layout
}
});
ResizeObserver
const observer = new ResizeObserver(entries => { // Element changed size });
This is useful when you care about the dimensions of a specific element.
For example:
observer.observe(document.querySelector('.chart'));
So window.resize for viewport changes while ResizeObserver for element size changes.
Real example: Responsive component
Imagine a reusable card component:
<div class="card"> <h2>Sales</h2> <div class="chart"></div> </div>
The chart should behave differently depending on the width of the card.
We could write:
const card = document.querySelector('.card');
const observer = new ResizeObserver(entries => {
const width = entries[0].contentRect.width;
if (width < 400) {
card.classList.add('compact');
} else {
card.classList.remove('compact');
}
});
observer.observe(card);
Notice something important here. The component responds to its own width, not the browser’s width. This makes the component much more reusable.
For example the same component can be placed in:
- a sidebar
- modal
- dashboard
and it can independently determine how much space it has.
Stopping Observation
If you no longer need to observe an element, call:
observer.unobserve(element);
Example:
const box = document.querySelector('.box');
observer.unobserve(box);
If you want to stop observing all elements:
observer.disconnect();
This is especially important when working with dynamically created components.
ResizeObserver in React
ResizeObserver works particularly well with React components.
For example:
import { useEffect, useRef, useState } from 'react';
function Box()
{
const ref = useRef(null);
const [width, setWidth] = useState(0);
useEffect(() => {
const element = ref.current;
if (!element) { return; }
const observer = new ResizeObserver(entries => {
setWidth(entries[0].contentRect.width);
});
observer.observe(element);
return () => { observer.disconnect(); };
}, []);
return (
<div ref={ref}> Width: {width}px </div>
)
}
The important part is the cleanup function:
return () => {
observer.disconnect();
};
This prevents the observer from continuing after the component is unmounted.


