DEV Community

Cover image for MutationObserver, IntersectionObserver, ResizeObserver - What/Why/How
Tomasz Kudlinski
Tomasz Kudlinski

Posted on

MutationObserver, IntersectionObserver, ResizeObserver - What/Why/How

During the life of web developer comes a moment when you have to build infinite scrolling list, react to the changes of the size of given element or its children or implement some behaviour dependant on the visibility of the object in the viewport. Observer's family can help you while working on mentioned tasks.

Background vector created by dooder - www.freepik.com

1. IntersectionObserver

What

thanks to it you can asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport.

Why

You might use it in below cases:

  • Lazy-loading of images
  • Implementing "infinite scrolling"
  • Reporting of visibility of advertisements etc.

How

const elements = document.querySelectorAll('.elt');
const options = {
  root: null, // set document viewport as root
  rootMargin: '0px', // margin around root
  threshold: 1.0 // 1.0 means that when 100% of the target is visible 
  //inside the root, then observer callback is invoked.
};

const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (entry.intersectionRatio > 0) {
      console.log('in viewport');
    } else {
      console.log('out of viewport');
    }
  });
}, options);

elements.forEach(elt => {
  observer.observe(elt);
});

Link to the docs

2. MutationObserver

What

It will be helpful if you need to watch for DOM tree changes.

Why

MutationObserver will tell you when the DOM element's child was removed, added or any of attributes of any DOM tree elements was changed.

How

const element = document.querySelector("#element");
const options = {
  childList: true, // listen to listen to children being added or removed
  attributes: true, // listen to attributes changes
  subtree: true // omit or set to false to observe only changes to the parent node
}

const callback = (mutationList, observer) => {
  mutationList.forEach((mutation) => {
    switch(mutation.type) {
      case 'childList':
         // check mutation.addedNodes or mutation.removedNodes
        break;
      case 'attributes':
        /* An attribute value changed on the element in
           mutation.target; the attribute name is in
           mutation.attributeName and its previous value is in
           mutation.oldValue */
        break;
    }
  });
}

const observer = new MutationObserver(callback);
observer.observe(element, options);

Link to the docs

3. ResizeObserver

What

It reports about changes of the dimensions of the element.

Why

It can be useful if you would like to listen to changes of the viewport (portrait vs landscape) or just you have some external content and you would like to react to it changes.

How

const elements = document.querySelectorAll('.elt');

const observer = new ResizeObserver(entries => {
  entries.forEach(entry => {
    const width = Math.floor(entry.contentRect.width);
    const height = Math.floor(entry.contentRect.height);
    // execute some logic based on width and height params
  }
});

elements.forEach(elt => {
  observer.observe(elt);
});

Link to the docs

Top comments (4)

Collapse
 
maciekgrzybek profile image
Maciek Grzybek

Observers are really awesome, but I feel like still not enough people know about them 😔

Collapse
 
emmanuelagarry profile image
emmanuel • Edited

That's true. I just knew about mutation observer. I wish I knew about it since. It would have saved me a lot of stress.

Collapse
 
tkudlinski profile image
Tomasz Kudlinski

exactly, but I think sooner or later every developer is thankful that they exists

Collapse
 
jaeyson profile image
Jaeyson Anthony Y.

the only thing i know here is intersection, quite handy with lazy load and infintescrolling. should i use both the observer with lazy attribute or pick one? which one you prefer?