or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

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

platform.mddocs/

Platform API

The Platform API provides the DOM-specific implementation for Floating UI's core positioning algorithms. It abstracts DOM operations like element measurements, clipping detection, and coordinate calculations, making it possible for the core library to work across different environments.

Capabilities

Platform Object

The main platform object that provides all DOM-specific implementations required by Floating UI core.

/**
 * DOM platform implementation providing element measurements and positioning calculations
 */
const platform: Platform;

interface Platform {
  // Required methods
  getElementRects(args: {
    reference: ReferenceElement;
    floating: FloatingElement;
    strategy: Strategy;
  }): Promise<ElementRects>;
  getClippingRect(args: {
    element: Element;
    boundary: Boundary;
    rootBoundary: RootBoundary;
    strategy: Strategy;
  }): Promise<Rect>;
  getDimensions(element: Element): Promise<Dimensions>;
  
  // Optional methods
  convertOffsetParentRelativeRectToViewportRelativeRect?(args: {
    elements?: Elements;
    rect: Rect;
    offsetParent: Element;
    strategy: Strategy;
  }): Promise<Rect>;
  getOffsetParent?(
    element: Element,
    polyfill?: (element: HTMLElement) => Element | null
  ): Promise<Element | Window>;
  isElement?(value: unknown): Promise<boolean>;
  getDocumentElement?(element: Element): Promise<HTMLElement>;
  getClientRects?(element: Element): Promise<Array<ClientRectObject>>;
  isRTL?(element: Element): Promise<boolean>;
  getScale?(element: HTMLElement): Promise<{x: number; y: number}>;
}

Usage Examples:

import { computePosition, platform } from "@floating-ui/dom";

// The platform is used automatically by computePosition
await computePosition(reference, floating, {
  platform, // Usually not needed - platform is default
  middleware: [/* ... */]
});

// Custom platform usage (advanced)
const customPlatform = {
  ...platform,
  getElementRects: async (args) => {
    // Custom implementation
    const rects = await platform.getElementRects(args);
    // Modify rects if needed
    return rects;
  }
};

await computePosition(reference, floating, {
  platform: customPlatform,
  middleware: [/* ... */]
});

Required Platform Methods

Get Element Rects

Returns the client rects for the reference and floating elements.

/**
 * Gets the client rects for reference and floating elements
 * @param args - Element rect calculation arguments
 * @returns Promise resolving to element rects
 */
getElementRects(args: {
  reference: ReferenceElement;
  floating: FloatingElement;
  strategy: Strategy;
}): Promise<ElementRects>;

interface ElementRects {
  reference: Rect;
  floating: Rect;
}

Get Clipping Rect

Returns the clipping rect of the given element.

/**
 * Gets the clipping rect of the given element
 * @param args - Clipping rect calculation arguments  
 * @returns Promise resolving to clipping rect
 */
getClippingRect(args: {
  element: Element;
  boundary: Boundary;
  rootBoundary: RootBoundary;
  strategy: Strategy;
}): Promise<Rect>;

type Boundary = 'clippingAncestors' | Element | Array<Element> | Rect;
type RootBoundary = 'viewport' | 'document' | Rect;

Get Dimensions

Returns the dimensions of the given element.

/**
 * Gets the dimensions of the given element
 * @param element - Element to measure
 * @returns Promise resolving to element dimensions
 */
getDimensions(element: Element): Promise<Dimensions>;

interface Dimensions {
  width: number;
  height: number;
}

Optional Platform Methods

Convert Offset Parent Relative Rect to Viewport Relative Rect

Converts coordinates from offset parent relative to viewport relative.

/**
 * Converts coordinates from offset parent relative to viewport relative
 * @param args - Coordinate conversion arguments
 * @returns Promise resolving to viewport-relative rect
 */
convertOffsetParentRelativeRectToViewportRelativeRect?(args: {
  elements?: Elements;
  rect: Rect;
  offsetParent: Element;
  strategy: Strategy;
}): Promise<Rect>;

Get Offset Parent

Returns the offset parent of the given element.

/**
 * Gets the offset parent of the given element
 * @param element - Element to find offset parent for
 * @param polyfill - Optional polyfill function for offset parent detection
 * @returns Promise resolving to offset parent element or window
 */
getOffsetParent?(
  element: Element,
  polyfill?: (element: HTMLElement) => Element | null
): Promise<Element | Window>;

Is Element

Determines whether the given value is an element.

/**
 * Determines whether the given value is an element
 * @param value - Value to check
 * @returns Promise resolving to boolean indicating if value is element
 */
isElement?(value: unknown): Promise<boolean>;

Get Document Element

Returns the document element (root element) for the given element.

/**
 * Gets the document element (root element) for the given element
 * @param element - Element to find document element for
 * @returns Promise resolving to document element
 */
getDocumentElement?(element: Element): Promise<HTMLElement>;

Get Client Rects

Returns all client rects for the given element.

/**
 * Gets all client rects for the given element
 * @param element - Element to get client rects for
 * @returns Promise resolving to array of client rects
 */
getClientRects?(element: Element): Promise<Array<ClientRectObject>>;

interface ClientRectObject {
  x: number;
  y: number;
  width: number;
  height: number;
  top: number;
  right: number;
  bottom: number;
  left: number;
}

Is RTL

Determines whether the given element is in a right-to-left context.

/**
 * Determines whether the given element is in a right-to-left context
 * @param element - Element to check RTL status for
 * @returns Promise resolving to boolean indicating RTL status
 */
isRTL?(element: Element): Promise<boolean>;

Get Scale

Returns the scale transform values for the given element.

/**
 * Gets the scale transform values for the given element
 * @param element - Element to get scale values for
 * @returns Promise resolving to scale coordinates
 */
getScale?(element: HTMLElement): Promise<{x: number; y: number}>;

Platform Implementation Details

DOM-Specific Calculations

The DOM platform implementation handles various browser-specific concerns:

  • Viewport measurements: Accurately calculating viewport dimensions across browsers
  • Scroll offsets: Accounting for scroll positions in positioning calculations
  • Transform handling: Properly calculating positions when CSS transforms are applied
  • RTL support: Supporting right-to-left text direction layouts
  • Device pixel ratios: Handling high-DPI displays correctly

Browser Compatibility

The platform implementation includes fallbacks and polyfills for:

  • Older browsers: Graceful degradation for browsers lacking modern APIs
  • CSS feature detection: Checking for transform support and other CSS features
  • Mobile browsers: Handling mobile-specific viewport and scrolling behaviors
  • Cross-frame scenarios: Working correctly with iframes and cross-origin content

Performance Optimizations

The platform includes several optimizations:

  • Measurement caching: Caching expensive DOM measurements within a single computation cycle
  • Batch operations: Minimizing DOM reads and writes for better performance
  • Intersection optimization: Using efficient clipping detection algorithms
  • Memory management: Properly cleaning up observers and event listeners

Custom Platform Extensions

Extending the Platform

You can extend the default platform for custom needs:

import { platform as defaultPlatform } from "@floating-ui/dom";

const customPlatform = {
  ...defaultPlatform,
  
  // Override specific methods
  getDimensions: async (element) => {
    const dimensions = await defaultPlatform.getDimensions(element);
    
    // Add custom logic - e.g., minimum dimensions
    return {
      width: Math.max(dimensions.width, 100),
      height: Math.max(dimensions.height, 50)
    };
  },
  
  // Add logging to clipping calculations
  getClippingRect: async (args) => {
    console.log('Calculating clipping rect for:', args.element);
    return defaultPlatform.getClippingRect(args);
  }
};

// Use custom platform
await computePosition(reference, floating, {
  platform: customPlatform,
  middleware: [/* ... */]
});

Virtual Element Support

The platform automatically handles virtual elements (non-DOM positioning references):

import { computePosition } from "@floating-ui/dom";

// Virtual element example
const virtualElement = {
  getBoundingClientRect() {
    return {
      x: 100,
      y: 100, 
      width: 0,
      height: 0,
      top: 100,
      right: 100,
      bottom: 100,
      left: 100
    };
  }
};

// Platform handles virtual elements automatically
await computePosition(virtualElement, floating, {
  placement: 'bottom',
  middleware: [offset(10)]
});

Testing with Mock Platform

For testing, you can provide a mock platform:

const mockPlatform = {
  getElementRects: async () => ({
    reference: { x: 0, y: 0, width: 100, height: 50 },
    floating: { x: 0, y: 0, width: 200, height: 100 }
  }),
  getClippingRect: async () => ({
    x: 0, y: 0, width: 1000, height: 800
  }),
  getDimensions: async () => ({
    width: 200, height: 100
  })
};

// Use in tests
await computePosition(mockReference, mockFloating, {
  platform: mockPlatform,
  middleware: [/* ... */]
});

Integration with Floating UI Core

The platform serves as the bridge between Floating UI's platform-agnostic core algorithms and DOM-specific operations. This separation allows:

  • Portability: Core algorithms can work in different environments (DOM, Canvas, etc.)
  • Testability: Easy mocking and testing of positioning logic
  • Extensibility: Custom platforms for special use cases
  • Maintainability: Clear separation of concerns between algorithms and environment-specific code