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.
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: [/* ... */]
});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;
}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;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;
}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>;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>;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>;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>;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;
}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>;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}>;The DOM platform implementation handles various browser-specific concerns:
The platform implementation includes fallbacks and polyfills for:
The platform includes several optimizations:
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: [/* ... */]
});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)]
});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: [/* ... */]
});The platform serves as the bridge between Floating UI's platform-agnostic core algorithms and DOM-specific operations. This separation allows: