Element Resize Detector is a JavaScript library that provides optimized cross-browser resize detection for DOM elements. It offers up to 37x better performance than related approaches through two detection strategies: scroll-based (recommended) and object-based.
npm install element-resize-detectorNode.js/CommonJS:
var elementResizeDetectorMaker = require("element-resize-detector");ES modules (if using with a bundler):
import elementResizeDetectorMaker from "element-resize-detector";Browser (via script tag):
<script src="node_modules/element-resize-detector/dist/element-resize-detector.min.js"></script>This creates a global function elementResizeDetectorMaker.
var elementResizeDetectorMaker = require("element-resize-detector");
// Create detector with default options
var erd = elementResizeDetectorMaker();
// Listen to resize events
erd.listenTo(document.getElementById("test"), function(element) {
var width = element.offsetWidth;
var height = element.offsetHeight;
console.log("Size: " + width + "x" + height);
});
// High performance setup
var erdFast = elementResizeDetectorMaker({
strategy: "scroll"
});
// Listen to multiple elements
var elements = document.querySelectorAll(".resizable");
erdFast.listenTo(elements, function(element) {
// Handle resize for each element
});
// Cleanup when done
erd.uninstall(document.getElementById("test"));Element Resize Detector is built around several key components:
Creates an element resize detector instance with optional configuration.
/**
* Creates an element resize detector instance
* @param {Options} options - Optional configuration object
* @returns {ElementResizeDetector} Detector instance with public API methods
*/
function elementResizeDetectorMaker(options);
interface ElementResizeDetector {
listenTo(options: Options, elements: Element | Element[] | NodeList, listener: (element: Element) => void): void;
listenTo(elements: Element | Element[] | NodeList, listener: (element: Element) => void): void;
removeListener(element: Element, listener: (element: Element) => void): void;
removeAllListeners(element: Element): void;
uninstall(elements: Element | Element[] | NodeList): void;
initDocument(targetDocument: Document): void;
}Makes elements resize-detectable and starts listening to resize events.
/**
* Makes elements resize-detectable and starts listening to resize events
* @param {ListenToOptions} options - Options that override global options for this call (includes onReady callback)
* @param {Element|Element[]|NodeList} elements - Single element, array of elements, or element collection
* @param {Function} listener - Callback executed for each resize event, receives element as argument
*/
listenTo(options, elements, listener);
/**
* Overload without options parameter
* @param {Element|Element[]|NodeList} elements - Single element, array of elements, or element collection
* @param {Function} listener - Callback executed for each resize event, receives element as argument
*/
listenTo(elements, listener);Usage Example:
// With options
erd.listenTo({ callOnAdd: false }, element, function(el) {
console.log("Element resized:", el);
});
// Without options
erd.listenTo(element, function(el) {
console.log("Element resized:", el);
});
// Multiple elements
erd.listenTo([element1, element2], function(el) {
console.log("Element resized:", el);
});
// With onReady callback
erd.listenTo({
onReady: function() {
console.log("All elements are ready for detection");
// Safe to trigger size changes here
}
}, elements, function(el) {
console.log("Element resized:", el);
});Removes a specific listener from an element.
/**
* Removes a specific listener from an element
* @param {Element} element - DOM element to remove listener from
* @param {Function} listener - Specific listener function to remove
*/
removeListener(element, listener);Removes all listeners from an element without completely removing the detector.
/**
* Removes all listeners from an element without completely removing the detector
* @param {Element} element - DOM element to remove all listeners from
*/
removeAllListeners(element);Completely removes the detector and all listeners from elements.
/**
* Completely removes the detector and all listeners from elements
* @param {Element|Element[]|NodeList} elements - Elements to uninstall detector from
*/
uninstall(elements);Initializes the detector for elements in another document (e.g., iframe).
/**
* Initializes the detector for elements in another document (e.g., iframe)
* @param {Document} targetDocument - Document object to initialize for element detection
*/
initDocument(targetDocument);Usage Example:
// Initialize for iframe content
var iframe = document.getElementById("myFrame");
erd.initDocument(iframe.contentDocument);
// Now you can listen to elements in the iframe
var iframeElement = iframe.contentDocument.getElementById("resizable");
erd.listenTo(iframeElement, function(element) {
console.log("Iframe element resized");
});Options passed to elementResizeDetectorMaker(options):
interface Options {
/** Detection strategy to use. "scroll" is recommended for performance */
strategy?: "object" | "scroll";
/** Whether listeners should be called when added (guarantees initial call) */
callOnAdd?: boolean;
/** Enable debug logging for the listenTo method */
debug?: boolean;
/** Custom ID handler for generating and managing element IDs */
idHandler?: IdHandler;
/** Custom reporter for logs/warnings/errors. Set to false for quiet mode */
reporter?: Reporter | false;
/** Custom batch processor for handling resize events */
batchProcessor?: BatchProcessor;
/** Adds !important to injected CSS rules to avoid conflicts */
important?: boolean;
}
interface IdHandler {
/** Gets the resize detector id of the element */
get(element: Element, readonly?: boolean): string;
/** Generate and sets the resize detector id of the element */
set(element: Element): string;
}
interface Reporter {
log(message: string): void;
warn(message: string): void;
error(message: string): void;
}Default Values:
{
strategy: "object",
callOnAdd: true,
debug: false,
idHandler: /* internal default */,
reporter: /* internal default */,
batchProcessor: /* internal default */,
important: false
}Options that can be passed to individual listenTo calls to override global options:
interface ListenToOptions {
/** Override global callOnAdd setting for this listener */
callOnAdd?: boolean;
/** Override global debug setting for this listener */
debug?: boolean;
/** Callback invoked when all elements are ready for detection */
onReady?: () => void;
}"scroll""Scroll strategy is not supported on legacy Opera. Changing to object strategy.""Scroll strategy is not supported on IE9. Changing to object strategy."var erd = elementResizeDetectorMaker({
strategy: "scroll" // May automatically fallback to object strategy
});"object"var erd = elementResizeDetectorMaker({
strategy: "object"
});The library throws specific errors for various conditions:
Factory Function Errors:
Error: Invalid strategy name: [strategyName] when an unsupported strategy is specifiedlistenTo Function Errors:
Error: At least one element required. when no elements are providedError: Listener required. when no listener function is providedInvalid arguments. Must be a DOM element or a collection of DOM elements. (via reporter.error)Example Error Handling:
try {
var erd = elementResizeDetectorMaker({
strategy: "invalid-strategy"
});
} catch (error) {
console.error("Strategy error:", error.message);
// Fallback to default strategy
erd = elementResizeDetectorMaker();
}
// The library will automatically handle invalid elements via reporter
erd.listenTo("not-an-element", function() {}); // Logs error, doesn't throwThe reporter system handles warnings and errors during operation, and automatic strategy fallback occurs for unsupported browsers.
Position Changes: If the element has position: static it will be changed to position: relative. Any unintentional top/right/bottom/left/z-index styles will therefore be applied and absolute positioned children will be positioned relative to the element.
DOM Injection: A hidden element will be injected as a direct child to the element for detection purposes.
Document Initialization: For elements inside iframes or other documents, you must call initDocument() with the target document before listening to elements in that document.
Element State Management: The library maintains internal state for each element during the installation process:
listenTo calls for the same element are synchronized and share installation completion callbacksWhen working with iframes, initialize the iframe's document:
var iframe = document.getElementById("myFrame");
// Initialize when iframe loads
iframe.onload = function() {
erd.initDocument(iframe.contentDocument);
// Now you can listen to elements inside the iframe
var iframeElement = iframe.contentDocument.getElementById("resizable");
erd.listenTo(iframeElement, function(element) {
console.log("Iframe element resized");
});
};If you experience CSS conflicts, use the important option:
var erd = elementResizeDetectorMaker({
important: true // Adds !important to injected CSS rules
});