Skip to content

Instantly share code, notes, and snippets.

@edjw
Last active March 24, 2025 08:41
Show Gist options
  • Save edjw/2e70debdd3cf4017b618d4a2da49636c to your computer and use it in GitHub Desktop.
Save edjw/2e70debdd3cf4017b618d4a2da49636c to your computer and use it in GitHub Desktop.
onElementFound

onElementFound

A small JavaScript function that executes a callback when elements matching a CSS selector appear in the DOM. It works with elements that are available on page load and dynamically added later.

Usage

// Basic usage
onElementFound({
  selector: ".my-element",
  callback: (element) => {
    console.log("Element found!", element);
  },
});
// Usage with custom timeout
onElementFound({
  selector: "#dynamic-content",
  callback: (element) => {
    element.classList.add("processed");
  },
  timeout: 5000,
});
// Using additional options
onElementFound({
  selector: ".product-card",
  callback: (element) => {
    initializeProductCard(element);
  },
  // Only observe direct children being added/removed (not attributes)
  attributes: false,
  childList: true,
  subtree: false,
  timeout: 15000,
});
// Wait for an element that signals the app is ready,
// then perform an unrelated action
onElementFound({
  selector: ".app-initialized",
  callback: () => {
    // The element itself isn't used, but its presence
    // indicates the app is ready for additional operations

    // Load additional resources
    loadSecondaryAssets();
  },
});

API Reference

onElementFound(options) Watches the DOM for elements matching a CSS selector and executes a callback when found. Automatically disconnects after finding the element or when timeout expires.

Parameters

Option Type Default Description
selector string required CSS selector to match (e.g. "#page-title", ".nav-menu", "h1")
callback Function required Function to call when element is found, receives the element as parameter
timeout number 30000 Automatically disconnect after this many milliseconds (30 seconds by default)
attributes boolean true Whether to observe attribute changes
childList boolean true Whether to observe child elements
subtree boolean true Whether to observe the entire subtree

Returns: void - The function doesn't return anything

Browser Compatibility

Works in all modern browsers that support MutationObserver

/**
* Execute a callback when an element matching a CSS selector appears in the DOM
* @param {Object} options - Configuration options
* @param {string} options.selector - CSS selector to match (e.g. "#page-title", ".nav-menu", "h1")
* @param {Function} options.callback - Function to call when element is found, receives the element as parameter
* @param {number} [options.timeout=30000] - Automatically disconnect after this many milliseconds
* @param {boolean} [options.attributes=true] - Whether to observe attribute changes
* @param {boolean} [options.childList=true] - Whether to observe child elements
* @param {boolean} [options.subtree=true] - Whether to observe the entire subtree
* @return {void}
*/
function onElementFound(options = {}) {
// Set defaults for options
const {
selector,
callback,
timeout = 30000, // Default 30 second timeout
attributes = true,
childList = true,
subtree = true,
} = options;
// Check if required options are provided
if (!selector || typeof selector !== "string") {
console.error("A valid CSS selector is required");
return;
}
if (!callback || typeof callback !== "function") {
console.error("A callback function is required");
return;
}
// Store timeout ID
let timeoutId = null;
// Check if element already exists
const element = document.querySelector(selector);
if (element) {
callback(element);
return;
}
// Function to clean up observer and timeout
function disconnect() {
observer.disconnect();
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
}
}
// Create observer to watch for the element
const observer = new MutationObserver(() => {
const element = document.querySelector(selector);
if (element) {
// Element found, execute callback
callback(element);
disconnect();
}
});
// Start observing with configurable options
observer.observe(document.documentElement, {
attributes,
childList,
subtree,
});
// Set up timeout to automatically disconnect
timeoutId = setTimeout(() => {
disconnect();
console.log(
`onElementFound: Observer disconnected after ${timeout}ms timeout`
);
}, timeout);
}
// https://gist.github.com/edjw/2e70debdd3cf4017b618d4a2da49636c
function onElementFound(e={}){const{selector:t,callback:o,timeout:n=3e4,attributes:r=!0,childList:c=!0,subtree:i=!0}=e;if(!t||"string"!=typeof t)return void console.error("A valid CSS selector is required");if(!o||"function"!=typeof o)return void console.error("A callback function is required");let u=null;const s=document.querySelector(t);if(s)return void o(s);function l(){d.disconnect(),u&&(clearTimeout(u),u=null)}const d=new MutationObserver((()=>{const e=document.querySelector(t);e&&(o(e),l())}));d.observe(document.documentElement,{attributes:r,childList:c,subtree:i}),u=setTimeout((()=>{l(),console.log(`onElementFound: Observer disconnected after ${n}ms timeout`)}),n)}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment