​​ The Mutation Observer is a feature used to monitor changes in the DOM tree. It offers a modern and more efficient alternative to the older Mutation Events. Here are two instances where it proved to be a better solution compared to the infamously commonly seen timeout solution: ​

​ The Mutation Observer’s ability to efficiently detect DOM changes makes it a valuable tool for resolving various problems in web development. ​

In this article, we will discuss two similar problems that were resolved using the Mutation Observer. ​

For more information, you can read the documentation at the following link: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

At Leniolabs, we work with clients who already have their design systems, and in some cases, making changes to the components is not feasible. There are various reasons for this, such as the workload of the team responsible for the design system or the number of projects using the design system.

​ In such situations, we need to implement our adjustments to certain components. ​

Example 1: Confirmation Popover

In this example, we demonstrate how to handle the focus when a modal is opened asynchronously in response to the onClick event

​ In our system, we utilize a component called “collections” that enables users to add or delete the same set of elements. This functionality proves useful in forms where there’s a need to include repetitive data from other individuals or personal information. ​

In scenarios with multiple collections, our component provides the functionality to delete a particular group by clicking the “Remove” button, as shown in the image. ​

After clicking the “Remove” button, a confirmation popover appears, and one of the specific requirements is to focus on the “Yes” button to ensure smooth user interaction. ​

Please note that due to a delay between the “Remove” button click and the popover’s appearance, it becomes challenging to locate the “Yes” button programmatically, leading to a null result.

To ensure a smooth user experience and handle uncertain animation durations, we often utilize setTimeout to delay the appearance of an element after the animation completes. However, this approach lacks precision, and the exact timing remains unknown. ​

To address this issue effectively, we suggest an alternative method using the Mutation Observer. By employing this technique, we actively observe changes in the DOM and verify that the popover has been successfully added to the DOM tree when the isOpen flag is true. Consequently, we can set the focus on the target element with greater accuracy and efficiency, making the user interaction more reliable and seamless.

/*
This callback will be invoked when there are changes in the DOM.
​
Specifically, it will detect changes in the child list of the "body" element.
*/
const callback = (mutationList) => {
  mutationList.forEach((mutation) => {
    switch (mutation.type) {
      case "childList":
        if (isOpen) {
          focusRemoveConfirmation();
        }
        break;

      default:
        break;
    }
  });
};

const observerOptions = {
  childList: true,
  subtree: true,
};

/*
To set up the MutationObserver, create it by providing the necessary callback function.
The "observe" method takes two arguments:
​
  The first argument is the DOM element that needs to be watched for expected changes.
  The second argument is an options object that defines the conditions for detecting the changes.
*/
const observer = new MutationObserver(callback);
observer.observe(document.body, observerOptions);
export const focusRemoveConfirmation = () => {
  const removeConfirmation =
    document && document.getElementById("remove-confirmation");

  if (removeConfirmation) {
    removeConfirmation.focus();
  }
};

Example 2: Sidebar with Close Event Control

In this scenario, the challenge is to clear checkboxes on a closing sidebar with animation-induced delays

​ We showcase a sidebar component designed to showcase a list of selectable items. Once the user makes their selections, they can click the “ADD” button to transfer the chosen items to a separate list for further use. The sidebar also includes a close event control to manage its visibility.

Upon clicking the “ADD” button, the sidebar has been programmed to collapse with smooth animation, taking around 500ms to complete the collapse.

the wrong checkbox behavior
and the expected behavior

As a user, I expect the selected checkboxes to reset to their initial “unselected” state after submitting the data by clicking the “ADD” button. However, due to the 500ms delay in sidebar collapse, the clearing effect occurs too soon, leading to a visually awkward and poorly coordinated outcome.

To address this, we can implement a solution using setTimeout. By adding a line of code that waits for 500ms before executing the checkbox-clearing process, we ensure that the resetting effect occurs only after the sidebar has completely collapsed, resulting in a smoother and more synchronized user experience.

Solution using setTimeout: ​

setTimeout(function() {
  // Checkbox clearing here
}, 500);

​ In this code snippet, we have implemented a “setTimeout” function to introduce a 500ms delay before initiating the clearing process of selected checkboxes. This intentional delay allows us to synchronize the cleanup action with the completion of the sidebar collapse, resulting in a more coordinated and visually pleasing user experience. ​

Advantages: ​

Disadvantages: ​

​ Solution using Mutation Observer: ​

// To efficiently track changes in the sidebar's state, we can establish a MutationObserver.
// This observer will allow us to react to modifications in the sidebar and perform the necessary actions accordingly.

let observer = new MutationObserver(function(mutations) {
  // To check if the sidebar is no longer visible
  let sidebarVisible = false;
  for (let i = 0; i < mutations.length; i++) {
    if (
      mutations[i].target.className === "sidebar" &&
      mutations[i].target.style.display === "none"
    ) {
      sidebarVisible = false;
      break;
    }
  }
  
  // If the sidebar is no longer visible, clear the selected checkboxes
  if (!sidebarVisible) {
    // Checkbox clearing here
  }
});

// Set up the MutationObserver to monitor changes in the sidebar's state
observer.observe(document.body, {
  attributes: true,
  attributeFilter: ["style"],
  subtree: true
});

​ In this code snippet, we make effective use of the MutationObserver to monitor the sidebar’s state changes. Upon detecting the sidebar becoming invisible, we trigger the clearing of selected checkboxes. By leveraging the MutationObserver, we eliminate the need for specifying a fixed time duration, ensuring a flexible and adaptive solution that automatically adjusts to future changes in the sidebar collapse time. ​

Advantages: ​

Disadvantages: ​

​ In summary, the solution employing the MutationObserver is the most efficient choice for both scenarios. While it might involve a bit more complexity in implementation, it offers a more resilient and flexible approach compared to setTimeout. Moreover, any minor performance impact caused by using the MutationObserver is a negligible trade-off for obtaining a solution that seamlessly adjusts to potential future changes in the popover’s appearance time or the sidebar’s collapse.