Blog Resume

Observer APIs

WordCount:
378
Reading Time:
2 min read

Why you should care

Each Observer API solves a modern browser challenge efficiently. Use them together, and you can build highly dynamic UI behavior without any heavy event listeners or performance penalties. This is exactly where the Observer APIs shine.

  • IntersectionObserver → watch visibility and scrolling
  • MutationObserver → watch DOM changes
  • ResizeObserver → watch element size changes

The Intersection Observer

The IntersectionObserver allows you to detect when an element enters or exits the viewport (or any scrollable container).

It’s the foundation of lazy loading, infinite scrolling, impression tracking, and scroll-based animations—all without janky scroll event listeners firing every few milliseconds.

Implementing Infinite Scroll

A classic use case: automatically loading more content when a sentinel element becomes visible.

const sentinel = document.querySelector("#load-more-trigger");

const observer = new IntersectionObserver(
  (entries) => {
    if (entries[0].isIntersecting) {
      loadMoreItems(); // Your pagination function
    }
  },
  {
    rootMargin: "200px", // preload before the user hits the bottom
  },
);

observer.observe(sentinel);

This gives you smooth, battery-friendly infinite scroll behavior with minimal code.


The Mutation Observer

MutationObserver watches for DOM changes—added/removed nodes, attribute updates, and text changes.

This becomes invaluable when dealing with dynamic content, third-party scripts, user input that modifies the DOM, or frameworks generating markup on the fly.

Implementing Dynamic Text Conversion

Suppose you want to let users type text into a content-editable area and automatically convert supported tags—such as :smile: or [b]bold[/b]—into actual HTML elements.

const editor = document.querySelector("#editor");

const observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    if (mutation.type === "childList" || mutation.type === "characterData") {
      editor.innerHTML = editor.innerHTML
        .replace(/:smile:/g, "šŸ˜„")
        .replace(/\[b\](.*?)\[\/b\]/g, "<strong>$1</strong>");
    }
  });
});

observer.observe(editor, {
  childList: true,
  characterData: true,
  subtree: true,
});

This is how you build lightweight custom text editors without a full framework.


The Resize Observer

ResizeObserver detects changes in an element’s size—not the window’s size, but the actual box size of any element you watch.

This unlocks full layout responsiveness at the component level, independent of media queries or global resize listeners.

Changing styles based on element size

Let’s say you’re tracking user-resizable elements and want them to become circles if they drop below 150Ɨ150px.

const box = document.querySelector(".box");

const observer = new ResizeObserver((entries) => {
  for (const entry of entries) {
    const { width, height } = entry.contentRect;

    if (width < 150 && height < 150) {
      box.style.borderRadius = "50%";
    } else {
      box.style.borderRadius = "0";
    }
  }
});

observer.observe(box);

Now the element reacts fluidly as the user resizes it.