Tooltip and popover positioning engine that automatically calculates optimal placement for UI elements with advanced positioning logic and overflow prevention
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Core createPopper function and instance management for tooltip and popover positioning with automatic updates and lifecycle management.
Creates a popper instance to position a popper element relative to a reference element.
/**
* Creates a popper instance to position a popper element relative to a reference element
* @param reference - Reference element or virtual element to position relative to
* @param popper - HTML element to be positioned (the tooltip/popover)
* @param options - Configuration options for positioning behavior
* @returns Instance object with methods to control the popper
*/
function createPopper(
reference: Element | VirtualElement,
popper: HTMLElement,
options?: Partial<Options>
): Instance;Usage Examples:
import { createPopper } from '@popperjs/core';
// Basic usage
const button = document.querySelector('#button');
const tooltip = document.querySelector('#tooltip');
const popperInstance = createPopper(button, tooltip);
// With options
const popperInstance = createPopper(button, tooltip, {
placement: 'bottom-start',
strategy: 'fixed',
modifiers: [
{
name: 'preventOverflow',
options: {
boundary: 'clippingParents',
},
},
],
});
// With callback on first update
const popperInstance = createPopper(button, tooltip, {
placement: 'top',
onFirstUpdate: (state) => {
console.log('Popper positioned at:', state.placement);
},
});The popper instance provides methods for controlling positioning and lifecycle.
interface Instance {
/** Current state of the popper */
state: State;
/** Destroy the popper instance and cleanup event listeners */
destroy(): void;
/** Force immediate synchronous update of popper position */
forceUpdate(): void;
/** Asynchronously update popper position (debounced) */
update(): Promise<Partial<State>>;
/** Update popper options and recalculate position */
setOptions(setOptionsAction: SetAction<Partial<Options>>): Promise<Partial<State>>;
}
type SetAction<S> = S | ((prev: S) => S);Usage Examples:
// Update positioning manually
await popperInstance.update();
// Force immediate update (synchronous)
popperInstance.forceUpdate();
// Update options
await popperInstance.setOptions({
placement: 'bottom',
});
// Update options with function
await popperInstance.setOptions((prevOptions) => ({
...prevOptions,
modifiers: [...prevOptions.modifiers, { name: 'flip', enabled: true }],
}));
// Cleanup
popperInstance.destroy();Configuration object for customizing popper behavior.
interface Options {
/** Initial placement of the popper relative to reference */
placement: Placement;
/** Array of modifiers to customize positioning behavior */
modifiers: Array<Partial<Modifier<any, any>>>;
/** CSS positioning strategy to use */
strategy: PositioningStrategy;
/** Callback executed after first update */
onFirstUpdate?: (state: Partial<State>) => void;
}
type Placement =
| 'auto' | 'auto-start' | 'auto-end'
| 'top' | 'top-start' | 'top-end'
| 'bottom' | 'bottom-start' | 'bottom-end'
| 'right' | 'right-start' | 'right-end'
| 'left' | 'left-start' | 'left-end';
type PositioningStrategy = 'absolute' | 'fixed';Usage Examples:
// Different placement options
const topPopper = createPopper(button, tooltip, { placement: 'top' });
const rightStartPopper = createPopper(button, tooltip, { placement: 'right-start' });
const autoPopper = createPopper(button, tooltip, { placement: 'auto' });
// Fixed positioning (useful in modals)
const fixedPopper = createPopper(button, tooltip, {
strategy: 'fixed',
placement: 'bottom',
});
// Custom modifiers
const customPopper = createPopper(button, tooltip, {
modifiers: [
{
name: 'offset',
options: { offset: [0, 10] },
},
{
name: 'flip',
enabled: false,
},
],
});Complete state information about the popper instance.
interface State {
/** Reference to DOM elements */
elements: {
reference: Element | VirtualElement;
popper: HTMLElement;
arrow?: HTMLElement;
};
/** Current options configuration */
options: Options;
/** Current computed placement */
placement: Placement;
/** CSS positioning strategy being used */
strategy: PositioningStrategy;
/** Ordered list of active modifiers */
orderedModifiers: Array<Modifier<any, any>>;
/** Computed rectangles for positioning */
rects: StateRects;
/** Scroll parent elements for both reference and popper */
scrollParents: {
reference: Array<Element | Window | VisualViewport>;
popper: Array<Element | Window | VisualViewport>;
};
/** Computed CSS styles to apply */
styles: { [key: string]: Partial<CSSStyleDeclaration> };
/** HTML attributes to apply */
attributes: { [key: string]: { [key: string]: string | boolean } };
/** Data from individual modifiers */
modifiersData: { [key: string]: any };
/** Whether positioning needs to be recalculated */
reset: boolean;
}
interface StateRects {
reference: Rect;
popper: Rect;
}
interface Rect {
width: number;
height: number;
x: number;
y: number;
}Usage Examples:
// Access current state
const { placement, rects } = popperInstance.state;
console.log('Current placement:', placement);
console.log('Popper dimensions:', rects.popper);
// Check modifier data
const offsetData = popperInstance.state.modifiersData.offset;
console.log('Applied offset:', offsetData);
// Get applied styles
const popperStyles = popperInstance.state.styles.popper;
console.log('Transform applied:', popperStyles.transform);Common error scenarios and handling patterns.
// Check if elements are valid before creating popper
function createSafePopper(referenceSelector, popperSelector, options) {
const reference = document.querySelector(referenceSelector);
const popper = document.querySelector(popperSelector);
if (!reference || !popper) {
throw new Error('Reference or popper element not found');
}
// Popper will handle invalid elements gracefully
return createPopper(reference, popper, options);
}
// Handle destroyed instances
let popperInstance = createPopper(button, tooltip);
// Later...
popperInstance.destroy();
popperInstance = null; // Clear reference
// Attempting to use destroyed instance will not throw but has no effectInstall with Tessl CLI
npx tessl i tessl/npm-popperjs--core