The auto-update functionality automatically updates the position of the floating element when necessary changes occur in the DOM or viewport. It should only be called when the floating element is mounted on the DOM or visible on the screen.
Automatically updates the position of the floating element when necessary, returning a cleanup function that should be invoked when the floating element is removed from the DOM or hidden from the screen.
/**
* Automatically updates position of floating element when necessary
* @param reference - The reference element to position relative to
* @param floating - The floating element to position
* @param update - Callback function to call when position should be updated
* @param options - Configuration options for auto-update behavior
* @returns Cleanup function to stop auto-updates
*/
function autoUpdate(
reference: ReferenceElement,
floating: FloatingElement,
update: () => void,
options?: AutoUpdateOptions
): () => void;
interface AutoUpdateOptions {
/**
* Whether to update the position when an overflow ancestor is scrolled.
* @default true
*/
ancestorScroll?: boolean;
/**
* Whether to update the position when an overflow ancestor is resized. This
* uses the native `resize` event.
* @default true
*/
ancestorResize?: boolean;
/**
* Whether to update the position when either the reference or floating
* elements resized. This uses a `ResizeObserver`.
* @default typeof ResizeObserver === 'function'
*/
elementResize?: boolean;
/**
* Whether to update the position when the reference relocated on the screen
* due to layout shift.
* @default typeof IntersectionObserver === 'function'
*/
layoutShift?: boolean;
/**
* Whether to update on every animation frame if necessary. Only use if you
* need to update the position in response to an animation using transforms.
* @default false
*/
animationFrame?: boolean;
}Usage Examples:
import { computePosition, autoUpdate } from "@floating-ui/dom";
const reference = document.querySelector('#reference');
const floating = document.querySelector('#floating');
// Update function that recalculates position
async function updatePosition() {
const { x, y } = await computePosition(reference, floating, {
placement: 'bottom-start',
middleware: [offset(10), flip(), shift()]
});
Object.assign(floating.style, {
left: `${x}px`,
top: `${y}px`,
});
}
// Start auto-updating - call initially and on changes
const cleanup = autoUpdate(reference, floating, updatePosition);
// Later, when floating element is removed or hidden
cleanup();import { autoUpdate } from "@floating-ui/dom";
// Disable certain update triggers
const cleanup = autoUpdate(reference, floating, updatePosition, {
ancestorScroll: true, // Update on ancestor scroll (default: true)
ancestorResize: true, // Update on ancestor resize (default: true)
elementResize: false, // Don't update on element resize
layoutShift: true, // Update on layout shift (default: true if supported)
animationFrame: false // Don't update on every frame (default: false)
});
// Animation-based updates (expensive - use carefully)
const animationCleanup = autoUpdate(reference, floating, updatePosition, {
animationFrame: true // Update on every animation frame
});
// Minimal configuration - only scroll updates
const minimalCleanup = autoUpdate(reference, floating, updatePosition, {
ancestorScroll: true,
ancestorResize: false,
elementResize: false,
layoutShift: false,
animationFrame: false
});import { computePosition, autoUpdate, offset, flip, shift } from "@floating-ui/dom";
class Tooltip {
private reference: Element;
private floating: HTMLElement;
private cleanup?: () => void;
constructor(reference: Element, floating: HTMLElement) {
this.reference = reference;
this.floating = floating;
}
private async updatePosition() {
const { x, y } = await computePosition(this.reference, this.floating, {
placement: 'top',
middleware: [
offset(8),
flip(),
shift({ padding: 5 })
]
});
Object.assign(this.floating.style, {
position: 'absolute',
left: `${x}px`,
top: `${y}px`,
});
}
show() {
this.floating.style.display = 'block';
// Start auto-updating when shown
this.cleanup = autoUpdate(
this.reference,
this.floating,
() => this.updatePosition(),
{
ancestorScroll: true,
ancestorResize: true,
elementResize: true,
layoutShift: true
}
);
// Initial position calculation
this.updatePosition();
}
hide() {
this.floating.style.display = 'none';
// Stop auto-updating when hidden
if (this.cleanup) {
this.cleanup();
this.cleanup = undefined;
}
}
destroy() {
this.hide();
// Additional cleanup if needed
}
}
// Usage
const tooltip = new Tooltip(referenceElement, floatingElement);
tooltip.show(); // Starts auto-updating
tooltip.hide(); // Stops auto-updatingancestorScroll)Listens for scroll events on all overflow ancestors of both the reference and floating elements. This ensures the floating element repositions when any containing scroll area is scrolled.
// Enabled by default - floating element updates when any ancestor scrolls
autoUpdate(reference, floating, update, {
ancestorScroll: true
});ancestorResize)Listens for resize events on all overflow ancestors of both elements. This handles cases where container elements change size, affecting the available space for positioning.
// Enabled by default - floating element updates when any ancestor resizes
autoUpdate(reference, floating, update, {
ancestorResize: true
});elementResize)Uses a ResizeObserver to monitor size changes of both the reference and floating elements. This is essential when the elements themselves change size due to content changes.
// Enabled by default (if ResizeObserver is available)
autoUpdate(reference, floating, update, {
elementResize: true
});layoutShift)Uses an IntersectionObserver to detect when the reference element moves due to layout changes, such as dynamic content insertion or CSS changes.
// Enabled by default (if IntersectionObserver is available)
autoUpdate(reference, floating, update, {
layoutShift: true
});animationFrame)Updates on every animation frame. This is expensive and should only be used when you need to update the position in response to animations using transforms or other continuous changes.
// Disabled by default - use only when necessary
autoUpdate(reference, floating, update, {
animationFrame: true
});Always call the cleanup function returned by autoUpdate when the floating element is no longer needed. This prevents memory leaks and unnecessary computations.
const cleanup = autoUpdate(reference, floating, update);
// IMPORTANT: Call cleanup when done
cleanup();Disable unnecessary update triggers to improve performance:
// For static tooltips that don't need resize updates
autoUpdate(reference, floating, update, {
elementResize: false,
ancestorResize: false
});
// For floating elements in stable layouts
autoUpdate(reference, floating, update, {
layoutShift: false
});Only use animationFrame: true when absolutely necessary, as it can be performance-intensive:
// ❌ Avoid unless truly needed
autoUpdate(reference, floating, update, {
animationFrame: true
});
// ✅ Better for most use cases
autoUpdate(reference, floating, update, {
ancestorScroll: true,
ancestorResize: true,
elementResize: true,
layoutShift: true
});Auto-update features depend on modern browser APIs:
elementResize option (widely supported)layoutShift option (widely supported)The auto-update system gracefully degrades in older browsers by disabling unsupported features while maintaining core scroll and resize functionality.