Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      Google’s Agent2Agent protocol finds new home at the Linux Foundation

      June 23, 2025

      Decoding The SVG path Element: Curve And Arc Commands

      June 23, 2025

      This week in AI dev tools: Gemini 2.5 Pro and Flash GA, GitHub Copilot Spaces, and more (June 20, 2025)

      June 20, 2025

      Gemini 2.5 Pro and Flash are generally available and Gemini 2.5 Flash-Lite preview is announced

      June 19, 2025

      Best early Prime Day Nintendo Switch deals: My 17 favorite sales live now

      June 23, 2025

      How I use VirtualBox to run any OS on my Mac – including Linux

      June 23, 2025

      Apple will give you a free pair of AirPods when you buy a MacBook or iPad for school – here’s who’s eligible

      June 23, 2025

      How Apple’s biggest potential acquisition ever could perplex AI rivals like Google

      June 23, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      Music Streaming Platform using PHP and MySQL

      June 23, 2025
      Recent

      Music Streaming Platform using PHP and MySQL

      June 23, 2025

      Solutions That Benefit Everyone – Why Inclusive Design Matters for All

      June 23, 2025

      Reducing Barriers Across Industries Through Inclusive Design

      June 23, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      Windows 11 Installation Assistant Download: 2025 Guide

      June 23, 2025
      Recent

      Windows 11 Installation Assistant Download: 2025 Guide

      June 23, 2025

      Didn’t Receive Gears of War: Reloaded Code? Explainer

      June 23, 2025

      Fix Vibrant Visuals Greyed Out in Minecraft Bedrock

      June 23, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»News & Updates»A Better API for the Intersection and Mutation Observers

    A Better API for the Intersection and Mutation Observers

    June 23, 2025

    In a previous article, I showed you how to refactor the Resize Observer API into something way simpler to use:

    // From this
    const observer = new ResizeObserver(observerFn)
    
    function observerFn (entries) {
      for (let entry of entries) {
        // Do something with each entry
      }
    }
    
    const element = document.querySelector('#some-element')
    observer.observe(element);
    // To this 
    const node = document.querySelector('#some-element')
    const obs = resizeObserver(node, {
      callback({ entry }) {
        // Do something with each entry
      }
    })

    Today, we’re going to do the same for MutationObserver and IntersectionObserver.

    Refactoring Mutation Observer

    MutationObserver has almost the same API as that of ResizeObserver. So we can practically copy-paste the entire chunk of code we wrote for resizeObserver to mutationObserver.

    export function mutationObserver(node, options = {}) {
      const observer = new MutationObserver(observerFn)
      const { callback, ...opts } = options
      observer.observe(node, opts)
    
      function observerFn(entries) {
        for (const entry of entries) {
          // Callback pattern
          if (options.callback) options.callback({ entry, entries, observer })
          // Event listener pattern
          else {
            node.dispatchEvent(
              new CustomEvent('mutate', {
                detail: { entry, entries, observer },
              })
            )
          }
        }
      }
    }

    You can now use mutationObserver with the callback pattern or event listener pattern.

    const node = document.querySelector('.some-element')
    
    // Callback pattern 
    const obs = mutationObserver(node, {
      callback ({ entry, entries }) {
        // Do what you want with each entry
      }
    })
    
    // Event listener pattern
    node.addEventListener('mutate', event => {
      const { entry } = event.detail
      // Do what you want with each entry
    })

    Much easier!

    Disconnecting the observer

    Unlike ResizeObserver who has two methods to stop observing elements, MutationObserver only has one, the disconnect method.

    export function mutationObserver(node, options = {}) {
      // ... 
      return {
        disconnect() {
          observer.disconnect()
        }
      }
    }

    But, MutationObserver has a takeRecords method that lets you get unprocessed records before you disconnect. Since we should takeRecords before we disconnect, let’s use it inside disconnect.

    To create a complete API, we can return this method as well.

    export function mutationObserver(node, options = {}) {
      // ... 
      return {
        // ...
        disconnect() {
          const records = observer.takeRecords()
          observer.disconnect()
          if (records.length > 0) observerFn(records)
        }
      }
    }

    Now we can disconnect our mutation observer easily with disconnect.

    const node = document.querySelector('.some-element')
    const obs = mutationObserver(/* ... */)
    
    obs.disconnect()

    MutationObserver’s observe options

    In case you were wondering, MutationObserver’s observe method can take in 7 options. Each one of them determines what to observe, and they all default to false.

    • subtree: Monitors the entire subtree of nodes
    • childList: Monitors for addition or removal children elements. If subtree is true, this monitors all descendant elements.
    • attributes: Monitors for a change of attributes
    • attributeFilter: Array of specific attributes to monitor
    • attributeOldValue: Whether to record the previous attribute value if it was changed
    • characterData: Monitors for change in character data
    • characterDataOldValue: Whether to record the previous character data value

    Refactoring Intersection Observer

    The API for IntersectionObserver is similar to other observers. Again, you have to:

    1. Create a new observer: with the new keyword. This observer takes in an observer function to execute.
    2. Do something with the observed changes: This is done via the observer function that is passed into the observer.
    3. Observe a specific element: By using the observe method.
    4. (Optionally) unobserve the element: By using the unobserve or disconnect method (depending on which Observer you’re using).

    But IntersectionObserver requires you to pass the options in Step 1 (instead of Step 3). So here’s the code to use the IntersectionObserver API.

    // Step 1: Create a new observer and pass in relevant options
    const options = {/*...*/}
    const observer = new IntersectionObserver(observerFn, options)
    
    // Step 2: Do something with the observed changes
    function observerFn (entries) {
      for (const entry of entries) {
        // Do something with entry
      }
    }
    
    // Step 3: Observe the element
    const element = document.querySelector('#some-element')
    observer.observe(element)
    
    // Step 4 (optional): Disconnect the observer when we're done using it
    observer.disconnect(element)

    Since the code is similar, we can also copy-paste the code we wrote for mutationObserver into intersectionObserver. When doing so, we have to remember to pass the options into IntersectionObserver and not the observe method.

    export function mutationObserver(node, options = {}) {
      const { callback, ...opts } = options
      const observer = new MutationObserver(observerFn, opts)
      observer.observe(node)
    
      function observerFn(entries) {
        for (const entry of entries) {
          // Callback pattern
          if (options.callback) options.callback({ entry, entries, observer })
          // Event listener pattern
          else {
            node.dispatchEvent(
              new CustomEvent('intersect', {
                detail: { entry, entries, observer },
              })
            )
          }
        }
      }
    }

    Now we can use intersectionObserver with the same easy-to-use API:

    const node = document.querySelector('.some-element')
    
    // Callback pattern 
    const obs = intersectionObserver(node, {
      callback ({ entry, entries }) {
        // Do what you want with each entry
      }
    })
    
    // Event listener pattern
    node.addEventListener('intersect', event => {
      const { entry } = event.detail
      // Do what you want with each entry
    })

    Disconnecting the Intersection Observer

    IntersectionObserver‘s methods are a union of both resizeObserver and mutationObserver. It has four methods:

    • observe: observe an element
    • unobserve: stops observing one element
    • disconnect: stops observing all elements
    • takeRecords: gets unprocessed records

    So, we can combine the methods we’ve written in resizeObserver and mutationObserver for this one:

    export function intersectionObserver(node, options = {}) {
      // ...
      return {
        unobserve(node) {
          observer.unobserve(node)
        },
    
        disconnect() {
          // Take records before disconnecting.
          const records = observer.takeRecords()
          observer.disconnect()
          if (records.length > 0) observerFn(records)
        },
        
        takeRecords() {
          return observer.takeRecords()
        },
      }
    }

    Now we can stop observing with the unobserve or disconnect method.

    const node = document.querySelector('.some-element')
    const obs = intersectionObserver(node, /*...*/)
    
    // Disconnect the observer
    obs.disconnect()

    IntersectionObserver options

    In case you were wondering, IntersectionObserver takes in three options:

    • root: The element used to check if observed elements are visible
    • rootMargin: Lets you specify an offset amount from the edges of the root
    • threshold: Determines when to log an observer entry

    Here’s an article to help you understand IntersectionObserver options.

    Using this in practice via Splendid Labz

    Splendid Labz has a utils library that contains resizeObserver, mutationObserver and IntersectionObserver.

    You can use them if you don’t want to copy-paste the above snippets into every project.

    import { 
      resizeObserver, 
      intersectionObserver, 
      mutationObserver 
    } from 'splendidlabz/utils/dom'
    
    const mode = document.querySelector(‘some-element’)
    
    const resizeObs = resizeObserver(node, /* ... */)
    const intersectObs = intersectionObserver(node, /* ... */)
    const mutateObs = mutationObserver(node, /* ... */)

    Aside from the code we’ve written together above (and in the previous article), each observer method in Splendid Labz is capable of letting you observe and stop observing multiple elements at once (except mutationObserver because it doesn’t have a unobserve method)

    const items = document.querySelectorAll('.elements')
    const obs = resizeObserver(items, {
      callback ({ entry, entries }) {
        /* Do what you want here */
      }
    })
    
    // Unobserves two items at once
    const subset = [items[0], items[1]]
    obs.unobserve(subset)

    So it might be just a tad easier to use the functions I’ve already created for you. 😉

    Shameless Plug: Splendid Labz contains a ton of useful utilities — for CSS, JavaScript, Astro, and Svelte — that I have created over the last few years.

    I’ve parked them all in into Splendid Labz, so I no longer need to scour the internet for useful functions for most of my web projects. If you take a look, you might just enjoy what I’ve complied!

    (I’m still making the docs at the time of writing so it can seem relatively empty. Check back every now and then!)

    Learning to refactor stuff

    If you love the way I explained how to refactor the observer APIs, you may find how I teach JavaScript interesting.

    In my JavaScript course, you’ll learn to build 20 real life components. We’ll start off simple, add features, and refactor along the way.

    Refactoring is such an important skill to learn — and in here, I make sure you got cement it into your brain.

    That’s it! Hope you had fun reading this piece!


    A Better API for the Intersection and Mutation Observers originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

    Source: Read MoreÂ

    Facebook Twitter Reddit Email Copy Link
    Previous ArticleDistribution Release: IPFire 2.29 Core 195
    Next Article Benchmarking the Banana Pi BPI-F3 Single Board Computer

    Related Posts

    News & Updates

    Best early Prime Day Nintendo Switch deals: My 17 favorite sales live now

    June 23, 2025
    News & Updates

    How I use VirtualBox to run any OS on my Mac – including Linux

    June 23, 2025
    Leave A Reply Cancel Reply

    For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

    Continue Reading

    Nvidia Released Llama-3.1-Nemotron-Ultra-253B-v1: A State-of-the-Art AI Model Balancing Massive Scale, Reasoning Power, and Efficient Deployment for Enterprise Innovation

    Nvidia Released Llama-3.1-Nemotron-Ultra-253B-v1: A State-of-the-Art AI Model Balancing Massive Scale, Reasoning Power, and Efficient Deployment for Enterprise Innovation

    Machine Learning

    CVE-2025-49864 – AFS Analytics Missing Authorization Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    I found the best Elden Ring Nightreign deal you’ll see before launch — save nearly $10 on FromSoftware’s co-op spinoff

    News & Updates

    THUDM Releases GLM 4: A 32B Parameter Model Competing Head-to-Head with GPT-4o and DeepSeek-V3

    Machine Learning

    Highlights

    CVE-2025-31637 – LambertGroup SHOUT SQL Injection

    May 16, 2025

    CVE ID : CVE-2025-31637

    Published : May 16, 2025, 4:15 p.m. | 2 hours, 55 minutes ago

    Description : Improper Neutralization of Special Elements used in an SQL Command (‘SQL Injection’) vulnerability in LambertGroup SHOUT allows SQL Injection. This issue affects SHOUT: from n/a through 3.5.3.

    Severity: 8.5 | HIGH

    Visit the link for more details, such as CVSS details, affected products, timeline, and more…

    Console UX on a Windows PC gaming handheld? ‘Winhanced’ wants to beat Microsoft and Xbox to the punch.

    June 4, 2025

    CVE-2025-39481 – Apache Eventer SQL Injection

    May 16, 2025

    This Linux distro routes all your traffic through the Tor network – and it’s my new favorite for privacy

    June 23, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.