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

      Upwork Freelancers vs Dedicated React.js Teams: What’s Better for Your Project in 2025?

      August 1, 2025

      Is Agile dead in the age of AI?

      August 1, 2025

      Top 15 Enterprise Use Cases That Justify Hiring Node.js Developers in 2025

      July 31, 2025

      The Core Model: Start FROM The Answer, Not WITH The Solution

      July 31, 2025

      Finally, a sleek gaming laptop I can take to the office (without sacrificing power)

      August 1, 2025

      These jobs face the highest risk of AI takeover, according to Microsoft

      August 1, 2025

      Apple’s tariff costs and iPhone sales are soaring – how long until device prices are too?

      August 1, 2025

      5 ways to successfully integrate AI agents into your workplace

      August 1, 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

      Enhancing Laravel Queries with Reusable Scope Patterns

      August 1, 2025
      Recent

      Enhancing Laravel Queries with Reusable Scope Patterns

      August 1, 2025

      Everything We Know About Livewire 4

      August 1, 2025

      Everything We Know About Livewire 4

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

      YouTube wants to use AI to treat “teens as teens and adults as adults” — with the most age-appropriate experiences and protections

      August 1, 2025
      Recent

      YouTube wants to use AI to treat “teens as teens and adults as adults” — with the most age-appropriate experiences and protections

      August 1, 2025

      Sam Altman is afraid of OpenAI’s GPT-5 creation — “The Manhattan Project feels very fast, like there are no adults in the room”

      August 1, 2025

      9 new features that arrived on the Windows 11 Insider Program during the second half of July 2025

      August 1, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»News & Updates»A Better API for the Resize Observer

    A Better API for the Resize Observer

    June 16, 2025

    Resize Observer, Mutation Observer, and Intersection Observers are all good APIs that are more performant than their older counterparts:

    • ResizeObserver is better than the resize event
    • MutationObserver replaces the now deprecated Mutation Events
    • IntersectionObserver lets you do certain scroll interactions with less performance overhead.

    The API for these three observers are quite similar (but they have their differences which we will go into later). To use an observer, you have to follow the steps below:

    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).

    In practice, the above steps looks like this with the ResizeObserver.

    // Step 1: Create a new observer
    const observer = new ResizeObserver(observerFn)
    
    // Step 2: Do something with the observed changes
    function observerFn (entries) {
      for (let entry of entries) {
        // Do something with entry
      }
    }
    
    // Step 3: Observe an element
    const element = document.querySelector('#some-element')
    observer.observe(element);
    
    // Step 4 (optional): Disconnect the observer
    observer.disconnect(element)

    This looks clear (and understandable) after the steps have been made clear. But it can look like a mess without the comments:

    const observer = new ResizeObserver(observerFn)
    
    function observerFn (entries) {
      for (let entry of entries) {
        // Do something with entry
      }
    }
    
    const element = document.querySelector('#some-element')
    observer.observe(element);

    The good news is: I think we can improve the observer APIs and make them easier to use.

    The Resize Observer

    Let’s start with the ResizeObserver since it’s the simplest of them all. We’ll begin by writing a function that encapsulates the resizeObserver that we create.

    function resizeObserver () {
      // ... Do something
    }

    The easiest way to begin refactoring the ResizeObserver code is to put everything we’ve created into our resizeObserver first.

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

    Next, we can pass the element into the function to make it simpler. When we do this, we can eliminate the document.querySelector line.

    function resizeObserver (element) {
      const observer = new ResizeObserver(observerFn)
    
      function observerFn (entries) {
        for (let entry of entries) {
          // Do something with entry
        }
      }
    
      observer.observe(node);
    }

    This makes the function more versatile since we can now pass any element into it.

    // Usage of the resizeObserver function
    const node = document.querySelector('#some-element')
    const obs = resizeObserver(node)

    This is already much easier than writing all of the ResizeObserver code from scratch whenever you wish to use it.

    Next, it’s quite obvious that we have to pass in an observer function to the callback. So, we can potentially do this:

    // Not great
    function resizeObserver (node, observerFn) {
      const observer = new ResizeObserver(observerFn)
      observer.observe(node);
    }

    Since observerFn is always the same — it loops through the entries and acts on every entry — we could keep the observerFn and pass in a callback to perform tasks when the element is resized.

    // Better 
    function resizeObserver (node, callback) {
      const observer = new ResizeObserver(observerFn)
    
      function observerFn (entries) {
        for (let entry of entries) {
          callback(entry)
        }
      }
    
      observer.observe(node);
    }

    To use this, we can pass callback into the resizeObserver — this makes resizeObserver operate somewhat like an event listener which we are already familiar with.

    // Usage of the resizeObserver function
    const node = document.querySelector('#some-element')
    const obs = resizeObserver(node, entry => {
      // Do something with each entry
    })

    We can make the callback slightly better by providing both entry and entries. There’s no performance hit for passing an additional variable so there’s no harm providing more flexibility here.

    function resizeObserver (element, callback) {
      const observer = new ResizeObserver(observerFn)
    
      function observerFn (entries) {
        for (let entry of entries) {
          callback({ entry, entries })
        }
      }
    
      observer.observe(element);
    }

    Then we can grab entries in the callback if we need to.

    // Usage of the resizeObserver function
    // ...
    const obs = resizeObserver(node, ({ entry, entries }) => {
      // ...
    })

    Next, it makes sense to pass the callback as an option parameter instead of a variable. This will make resizeObserver more consistent with the mutationObserver and intersectionObserver functions that we will create in the next article.

    function resizeObserver (element, options = {}) {
      const { callback } = options
      const observer = new ResizeObserver(observerFn)
    
      function observerFn (entries) {
        for (let entry of entries) {
            callback({ entry, entries })
          }
      }
    
      observer.observe(element);
    }

    Then we can use resizeObserver like this.

    const obs = resizeObserver(node, {
      callback ({ entry, entries }) {
        // Do something ...
      }
    })

    The observer can take in an option too

    ResizeObserver‘s observe method can take in an options object that contains one property, box. This determines whether the observer will observe changes to content-box, border-box or device-pixel-content-box.

    So, we need to extract these options from the options object and pass them to observe.

    function resizeObserver (element, options = {}) {
      const { callback, ...opts } = options
      // ...
      observer.observe(element, opts);
    }

    Optional: Event listener pattern

    I prefer using callback because it’s quite straightforward. But if you want to use a standard event listener pattern, we can do that, too. The trick here is to emit an event. We’ll call it resize-obs since resize is already taken.

    function resizeObserver (element, options = {}) {
      // ...
      function observerFn (entries) {
        for (let entry of entries) {
          if (callback) callback({ entry, entries })
          else {
            node.dispatchEvent(
              new CustomEvent('resize-obs', {
                detail: { entry, entries },
              }),
            )
          }
        }
      }
    
      // ...
    }

    Then we can listen to the resize-obs event, like this:

    const obs = resizeObserver(node)
    node.addEventListener('resize-obs', event => {
      const { entry, entries } = event.detail
    })

    Again, this is optional.

    Unobserving the element

    One final step is to allow the user to stop observing the element(s) when observation is no longer required. To do this, we can return two of the observer methods:

    • unobserve: Stops observing one Element
    • disconnect: Stops observing all Elements
    function resizeObserver (node, options = {}) {
      // ...
      return {
        unobserve(node) {
          observer.unobserve(node)
        },
        
        disconnect() {
          observer.disconnet()
        }
      }
    }

    Both methods do the same thing for what we have built so far since we only allowed resizeObserver to observe one element. So, pick whatever method you prefer to stop observing the element.

    const obs = resizeObserver(node, {
      callback ({ entry, entries }) {
        // Do something ...
      }
    })
    
    // Stops observing all elements 
    obs.disconect()

    With this, we’ve completed the creation of a better API for the ResizeObserver — the resizeObserver function.

    Code snippet

    Here’s the code we’ve wrote for resizeObserver

    export function resizeObserver(node, options = {}) {
      const observer = new ResizeObserver(observerFn)
      const { callback, ...opts } = options
    
      function observerFn(entries) {
        for (const entry of entries) {
          // Callback pattern
          if (callback) callback({ entry, entries, observer })
          // Event listener pattern
          else {
            node.dispatchEvent(
              new CustomEvent('resize-obs', {
                detail: { entry, entries, observer },
              })
            )
          }
        }
      }
     
      observer.observe(node)
    
      return {
        unobserve(node) {
          observer.unobserve(node)
        },
        
        disconnect() {
          observer.disconnect()
        }
      }
    }

    Using this in practice via Splendid Labz

    Splendid Labz has a utils library that contains an enhanced version of the resizeObserver we made above. You can use it if you wanna use a enhanced observer, or if you don’t want to copy-paste the observer code into your projects.

    import { resizeObserver } from '@splendidlabz/utils/dom'
    
    const node = document.querySelector('.some-element')
    const obs = resizeObserver(node, {
      callback ({ entry, entries }) {
        /* Do what you want here */
      }
    })

    Bonus: The Splendid Labz resizeObserver is capable of observing multiple elements at once. It can also unobserve multiple elements at once.

    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) 

    Found this refactoring helpful?

    Refactoring is ultra useful (and important) because its a process that lets us create code that’s easy to use or maintain.

    If you found this refactoring exercise useful, you might just love how I teach JavaScript to budding developers in my Learn JavaScript course.

    In this course, you’ll learn to build 20 real-world components. For each component, we start off simple. Then we add features and you’ll learn to refactor along the way.

    That’s it!

    Hope you enjoyed this piece and see you in the next one.


    A Better API for the Resize Observer 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 ArticleInside the Frontier of AI, WebXR & Real-Time 3D: Crafting KODE Immersive
    Next Article AI-Native Product Development: 5 Pillars That Matter

    Related Posts

    News & Updates

    Finally, a sleek gaming laptop I can take to the office (without sacrificing power)

    August 1, 2025
    News & Updates

    These jobs face the highest risk of AI takeover, according to Microsoft

    August 1, 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

    CVE-2025-28986 – Webaholicson Epicwin Plugin CSRF SQL Injection

    Common Vulnerabilities and Exposures (CVEs)

    CVE-2025-5788 – TOTOLINK X15 HTTP POST Request Handler Buffer Overflow

    Common Vulnerabilities and Exposures (CVEs)

    Critical ABB EIBPORT Flaw: Update Now to Prevent Building Automation Hijacks!

    Security

    CVE-2025-6857 – HDF5 Stack-Based Buffer Overflow Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    Highlights

    Development

    How to Create Models in Your Django Project

    April 25, 2025

    If you’re building something with Django, there’s one thing you can’t skip: creating models. Models…

    Microsoft Waves Off Fee for Indie Devs, Rolls Out Major Store Upgrades – Check Details Here

    May 21, 2025

    CVE-2025-35978 – UpdateNavi UpdateNaviInstallService Remote Code Execution

    June 12, 2025

    Biome v2 – codename: Biotype

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

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