or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

auto-update.mdindex.mdmiddleware.mdplatform.md
tile.json

auto-update.mddocs/

Auto-Update

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.

Capabilities

Auto Update Function

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();

Advanced Auto-Update Configuration

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
});

Complete Integration Example

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-updating

Update Triggers

Ancestor Scroll (ancestorScroll)

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
});

Ancestor Resize (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
});

Element Resize (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
});

Layout Shift (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
});

Animation Frame (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
});

Performance Considerations

Cleanup Is Essential

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();

Selective Update Triggers

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
});

Animation Frame Usage

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
});

Browser Compatibility

Auto-update features depend on modern browser APIs:

  • ResizeObserver: Required for elementResize option (widely supported)
  • IntersectionObserver: Required for layoutShift option (widely supported)
  • Fallback: If these APIs are not available, the respective options are automatically disabled

The auto-update system gracefully degrades in older browsers by disabling unsupported features while maintaining core scroll and resize functionality.