Javascript

Monitoring Element Size Change With The Resize Observer in Javascript

Monitoring Element Size Change With The Resize Observer in Javascript

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 the contentBoxSize property.

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.

 

0 0 votes
Article Rating

What's your reaction?

Excited
0
Happy
0
Not Sure
0
Confused
0

You may also like

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted