CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-resize-observer-polyfill

A polyfill for the Resize Observer API that enables developers to observe changes to the dimensions of DOM elements

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

Resize Observer Polyfill

A polyfill for the Resize Observer API that enables developers to observe changes to the dimensions of DOM elements. This polyfill uses MutationObserver as the primary strategy with Mutation Events as a fallback for older browsers, avoiding polling mechanisms while maintaining performance.

Package Information

  • Package Name: resize-observer-polyfill
  • Package Type: npm
  • Language: JavaScript/TypeScript
  • Installation: npm install resize-observer-polyfill

Core Imports

import ResizeObserver from 'resize-observer-polyfill';

For CommonJS:

const ResizeObserver = require('resize-observer-polyfill');

For UMD (browser globals):

<script src="./node_modules/resize-observer-polyfill/dist/ResizeObserver.js"></script>
<!-- ResizeObserver is now available globally -->

Basic Usage

import ResizeObserver from 'resize-observer-polyfill';

// Create a ResizeObserver instance
const resizeObserver = new ResizeObserver((entries, observer) => {
  for (const entry of entries) {
    const { left, top, width, height } = entry.contentRect;

    console.log('Element:', entry.target);
    console.log(`Element's size: ${width}px x ${height}px`);
    console.log(`Element's paddings: ${top}px ; ${left}px`);
  }
});

// Start observing an element
resizeObserver.observe(document.body);

// Stop observing a specific element
resizeObserver.unobserve(document.body);

// Stop observing all elements
resizeObserver.disconnect();

Architecture

The polyfill implements the official ResizeObserver specification and follows these key principles:

  • Ponyfill Design: Doesn't modify global objects unless needed
  • Fallback Strategy: Uses MutationObserver primarily, with Mutation Events fallback for IE9-10
  • Performance Optimization: Batches and throttles updates with ~20ms delay
  • Spec Compliance: Follows the W3C ResizeObserver specification exactly
  • Browser Compatibility: Supports IE9+ through modern browsers

Capabilities

ResizeObserver Constructor

Creates a new ResizeObserver instance that can observe element size changes.

/**
 * Creates a new ResizeObserver instance
 * @param callback - Function called when observed elements change size
 */
constructor(callback: ResizeObserverCallback): ResizeObserver;

interface ResizeObserverCallback {
  (entries: ResizeObserverEntry[], observer: ResizeObserver): void;
}

Usage Example:

const observer = new ResizeObserver((entries, observer) => {
  entries.forEach(entry => {
    console.log('Size changed:', entry.contentRect);
  });
});

Element Observation

Methods for managing which elements are being observed for size changes.

/**
 * Begin observing size changes for the specified element
 * @param target - DOM element to observe
 */
observe(target: Element): void;

/**
 * Stop observing size changes for the specified element
 * @param target - DOM element to stop observing
 */
unobserve(target: Element): void;

/**
 * Stop observing all currently observed elements
 */
disconnect(): void;

Usage Examples:

// Start observing multiple elements
observer.observe(document.getElementById('sidebar'));
observer.observe(document.querySelector('.main-content'));

// Stop observing a specific element
observer.unobserve(document.getElementById('sidebar'));

// Stop all observations
observer.disconnect();

ResizeObserver Entry Data

The data structure provided to the callback function for each observed element.

interface ResizeObserverEntry {
  /** The observed element that changed size */
  readonly target: Element;
  /** The element's content rectangle with size information */
  readonly contentRect: DOMRectReadOnly;
}

interface DOMRectReadOnly {
  /** X coordinate of the rectangle */
  readonly x: number;
  /** Y coordinate of the rectangle */
  readonly y: number;
  /** Width of the rectangle */
  readonly width: number;
  /** Height of the rectangle */
  readonly height: number;
  /** Distance from top edge to element's top padding edge */
  readonly top: number;
  /** Distance from left edge to element's right padding edge */
  readonly right: number;
  /** Distance from top edge to element's bottom padding edge */
  readonly bottom: number;
  /** Distance from left edge to element's left padding edge */
  readonly left: number;
}

Usage Example:

const observer = new ResizeObserver((entries) => {
  entries.forEach(entry => {
    const { target, contentRect } = entry;
    const { width, height, top, left } = contentRect;
    
    // Update element based on its new size
    if (width < 300) {
      target.classList.add('compact');
    } else {
      target.classList.remove('compact');
    }
    
    console.log(`${target.tagName} is now ${width}x${height}`);
  });
});

Advanced Usage Patterns

Responsive Component Behavior

import ResizeObserver from 'resize-observer-polyfill';

class ResponsiveComponent {
  constructor(element) {
    this.element = element;
    this.observer = new ResizeObserver(this.handleResize.bind(this));
    this.observer.observe(element);
  }
  
  handleResize(entries) {
    const entry = entries[0];
    const { width } = entry.contentRect;
    
    // Apply different layouts based on width
    if (width < 480) {
      this.element.className = 'component mobile';
    } else if (width < 768) {
      this.element.className = 'component tablet';
    } else {
      this.element.className = 'component desktop';
    }
  }
  
  destroy() {
    this.observer.disconnect();
  }
}

Container Query Simulation

import ResizeObserver from 'resize-observer-polyfill';

function setupContainerQueries() {
  const containers = document.querySelectorAll('[data-container-query]');
  
  const observer = new ResizeObserver((entries) => {
    entries.forEach(entry => {
      const { target, contentRect } = entry;
      const { width } = contentRect;
      
      // Remove existing size classes
      target.classList.remove('sm', 'md', 'lg', 'xl');
      
      // Add appropriate size class
      if (width >= 1200) {
        target.classList.add('xl');
      } else if (width >= 992) {
        target.classList.add('lg');
      } else if (width >= 768) {
        target.classList.add('md');
      } else {
        target.classList.add('sm');
      }
    });
  });
  
  containers.forEach(container => observer.observe(container));
  
  return observer;
}

Browser Support and Limitations

Supported Browsers

  • Chrome, Firefox, Safari, Edge (modern versions)
  • Internet Explorer 9+
  • Mobile browsers (iOS Safari, Chrome Mobile, etc.)

Known Limitations

  • Notifications are delivered ~20ms after actual changes happen
  • Changes caused by dynamic pseudo-classes (:hover, :focus) are not tracked
  • Delayed transitions receive only one notification with final dimensions

Workaround for Pseudo-class Changes

// Add a short transition to trigger transitionend events
.element:hover {
  transition: opacity 0.001s;
}

TypeScript Support

The package includes full TypeScript definitions:

import ResizeObserver from 'resize-observer-polyfill';

const observer: ResizeObserver = new ResizeObserver(
  (entries: ResizeObserverEntry[], observer: ResizeObserver) => {
    entries.forEach((entry: ResizeObserverEntry) => {
      const rect: DOMRectReadOnly = entry.contentRect;
      console.log(`Size: ${rect.width}x${rect.height}`);
    });
  }
);

Error Handling

The ResizeObserver follows the same error handling as the native implementation:

const observer = new ResizeObserver((entries) => {
  // Callback errors don't break the observer
  entries.forEach(entry => {
    try {
      processEntry(entry);
    } catch (error) {
      console.error('Error processing resize entry:', error);
    }
  });
});

// Constructor validates arguments
try {
  new ResizeObserver(); // Throws TypeError
} catch (error) {
  console.error(error.message); // "1 argument required, but only 0 present."
}

try {
  new ResizeObserver.call(null, () => {}); // Throws TypeError  
} catch (error) {
  console.error(error.message); // "Cannot call a class as a function."
}
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/resize-observer-polyfill@1.5.x
Publish Source
CLI
Badge
tessl/npm-resize-observer-polyfill badge