Utility functions for web experiments with ELI (Experimentation Local Interface).
npm install @briannorman9/eli-utilsImport the utils in your ELI variant code:
import utils from '@eli/utils';Note: ELI's import system automatically resolves @eli/utils to @briannorman9/eli-utils from your project's node_modules.
Wait for the first element matching the selector to appear in the DOM. Note: This only matches the first element. Use waitForElements() to match all elements.
utils.waitForElement('#myElement').then(element => {
console.log('Element found:', element);
});Wait for all elements matching the selector to appear in the DOM. Note: This matches all elements. Use waitForElement() to match only the first element.
utils.waitForElements('.product-card').then(elements => {
elements.forEach(card => card.style.border = '2px solid red');
});Wait until a condition function returns true.
utils.waitUntil(() => document.readyState === 'complete');Select a single element (returns immediately, does not wait).
const button = utils.select('#myButton');Observe mutations on the first element matching the selector. The callback is called every time the element is mutated (attributes, children, text, etc.). Note: This only observes the first matching element. Use observeSelectors() to observe all elements.
Mutation types:
'childList'- Watch for child nodes being added/removed (default: true)'attributes'- Watch for attribute changes (default: true)'characterData'- Watch for text content changes (default: false)'subtree'- Watch all descendants, not just direct children (default: true)'attributeOldValue'- Include old attribute value in mutation record (default: false)'characterDataOldValue'- Include old text value in mutation record (default: false)'attributeFilter'- Array of attribute names to observe (only these attributes will trigger)
// Observe attribute changes on a button
const stopObserving = utils.observeSelector('#myButton', (element, mutation) => {
console.log('Button mutated:', mutation.type);
if (mutation.type === 'attributes') {
console.log('Attribute changed:', mutation.attributeName);
}
}, {
mutations: ['attributes'],
attributeFilter: ['class', 'disabled']
});
// Observe when children are added/removed
utils.observeSelector('.product-list', (element, mutation) => {
if (mutation.type === 'childList') {
console.log('Children changed:', mutation.addedNodes.length, 'added');
}
}, {
mutations: ['childList', 'subtree']
});Observe mutations on all elements matching the selector. The callback is called every time any matching element is mutated. Note: This observes all matching elements. Use observeSelector() to observe only the first element.
// Observe all product cards for attribute changes
const stopObserving = utils.observeSelectors('.product-card', (element, mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'data-price') {
console.log('Price changed on:', element);
}
}, {
mutations: ['attributes'],
attributeFilter: ['data-price', 'class']
});Add a class to an element.
utils.addClass('#myButton', 'active');Remove a class from an element.
utils.removeClass('#myButton', 'inactive');Toggle a class on an element.
utils.toggleClass('#myButton', 'active');Check if an element has a class.
if (utils.hasClass('#myButton', 'active')) {
console.log('Button is active');
}Add an event listener.
utils.on('#myButton', 'click', () => console.log('Clicked!'));Remove an event listener.
utils.off('#myButton', 'click', handler);Event delegation - attach event to parent, handle on children.
utils.delegate('#container', '.button', 'click', (e) => {
console.log('Button clicked:', e.target);
});Trigger a custom event.
utils.triggerEvent('experimentLoaded', { variant: 'v1' });Get a cookie value by name.
const userId = utils.getCookie('userId');Set a cookie.
utils.setCookie('userId', '12345', 30);Get a URL query parameter value.
const campaign = utils.getQueryParam('campaign');Get the viewport dimensions.
const { width, height } = utils.getViewport();Check if element is in viewport.
if (utils.isInViewport('#myElement')) {
console.log('Element is visible');
}Scroll element into view.
utils.scrollIntoView('#myElement', { behavior: 'smooth', block: 'center' });MIT