Floating UI for the web - DOM interface for positioning floating elements like tooltips, popovers, and dropdowns
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Floating UI DOM is the web implementation of Floating UI, providing a complete solution for positioning floating elements like tooltips, popovers, dropdowns, and menus. It wraps @floating-ui/core with DOM-specific interface logic and offers robust anchor positioning that ensures floating elements stay anchored to their reference elements while avoiding viewport collisions.
npm install @floating-ui/domimport { computePosition, autoUpdate } from "@floating-ui/dom";For middleware:
import {
offset,
flip,
shift,
autoPlacement,
size,
hide,
arrow,
inline,
limitShift,
detectOverflow
} from "@floating-ui/dom";For platform:
import { platform } from "@floating-ui/dom";For types:
import type {
Placement,
Strategy,
Middleware,
MiddlewareData,
MiddlewareState,
ComputePositionReturn,
VirtualElement,
Boundary,
RootBoundary
} from "@floating-ui/dom";CommonJS:
const { computePosition, autoUpdate, offset, flip, shift } = require("@floating-ui/dom");import { computePosition, offset, flip, shift } from "@floating-ui/dom";
// Get reference elements
const referenceElement = document.querySelector("#reference");
const floatingElement = document.querySelector("#floating");
// Compute position
const { x, y } = await computePosition(referenceElement, floatingElement, {
placement: 'bottom',
middleware: [
offset(10), // Add 10px offset
flip(), // Flip when overflowing
shift({ padding: 5 }) // Shift within padding
],
});
// Apply position to floating element
Object.assign(floatingElement.style, {
position: 'absolute',
left: `${x}px`,
top: `${y}px`,
});Floating UI DOM is built around several key components:
computePosition() function that calculates optimal placement coordinatesThe library uses a platform-agnostic core (@floating-ui/core) with DOM-specific implementations for element measurements, clipping detection, and coordinate calculations.
Computes the x and y coordinates that will place the floating element next to a given reference element.
function computePosition(
reference: ReferenceElement,
floating: FloatingElement,
options?: Partial<ComputePositionConfig>
): Promise<ComputePositionReturn>;
type ReferenceElement = Element | VirtualElement;
type FloatingElement = HTMLElement;
interface ComputePositionConfig {
placement?: Placement;
middleware?: Array<Middleware | null | undefined | false>;
strategy?: Strategy;
platform?: Platform;
}
interface ComputePositionReturn {
x: number;
y: number;
placement: Placement;
strategy: Strategy;
middlewareData: MiddlewareData;
}Automatically updates the position of the floating element when necessary, returning a cleanup function.
function autoUpdate(
reference: ReferenceElement,
floating: FloatingElement,
update: () => void,
options?: AutoUpdateOptions
): () => void;
interface AutoUpdateOptions {
ancestorScroll?: boolean;
ancestorResize?: boolean;
elementResize?: boolean;
layoutShift?: boolean;
animationFrame?: boolean;
}Collection of middleware functions that modify positioning behavior and provide positioning data.
// Core middleware functions
function offset(options?: OffsetOptions): Middleware;
function flip(options?: FlipOptions | Derivable<FlipOptions>): Middleware;
function shift(options?: ShiftOptions | Derivable<ShiftOptions>): Middleware;
function autoPlacement(options?: AutoPlacementOptions | Derivable<AutoPlacementOptions>): Middleware;
function size(options?: SizeOptions | Derivable<SizeOptions>): Middleware;
function hide(options?: HideOptions | Derivable<HideOptions>): Middleware;
function arrow(options: ArrowOptions | Derivable<ArrowOptions>): Middleware;
function inline(options?: InlineOptions | Derivable<InlineOptions>): Middleware;
// Utility
function detectOverflow(
state: MiddlewareState,
options?: DetectOverflowOptions | Derivable<DetectOverflowOptions>
): Promise<SideObject>;
function limitShift(options?: LimitShiftOptions | Derivable<LimitShiftOptions>): {
options: any;
fn: (state: MiddlewareState) => Coords;
};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}>;
}// Element types
interface VirtualElement {
getBoundingClientRect(): ClientRectObject;
getClientRects?(): Array<ClientRectObject> | DOMRectList;
contextElement?: Element;
}
interface ClientRectObject {
width: number;
height: number;
top: number;
right: number;
bottom: number;
left: number;
x: number;
y: number;
}
interface Elements {
reference: ReferenceElement;
floating: FloatingElement;
}
// Middleware types
interface Middleware {
name: string;
options?: any;
fn(state: MiddlewareState): Promise<MiddlewareReturn>;
}
interface MiddlewareState {
x: number;
y: number;
initialPlacement: Placement;
placement: Placement;
strategy: Strategy;
middlewareData: MiddlewareData;
rects: ElementRects;
elements: Elements;
}
interface MiddlewareReturn extends Partial<Coords> {
data?: {
[key: string]: any;
};
reset?: boolean | {
placement?: Placement;
rects?: boolean | ElementRects;
};
}
interface MiddlewareData {
[key: string]: any;
arrow?: Partial<Coords> & {
centerOffset: number;
alignmentOffset?: number;
};
autoPlacement?: {
index?: number;
overflows: Array<{
placement: Placement;
overflows: Array<number>;
}>;
};
flip?: {
index?: number;
overflows: Array<{
placement: Placement;
overflows: Array<number>;
}>;
};
hide?: {
referenceHidden?: boolean;
escaped?: boolean;
referenceHiddenOffsets?: SideObject;
escapedOffsets?: SideObject;
};
offset?: Coords & {
placement: Placement;
};
shift?: Coords & {
enabled: {
[key in Axis]: boolean;
};
};
size?: {
availableWidth: number;
availableHeight: number;
};
inline?: {
alignmentOffset: number;
};
}
// Utility types
type Derivable<T> = (state: MiddlewareState) => T;
type Boundary = 'clippingAncestors' | Element | Array<Element> | Rect;
type RootBoundary = 'viewport' | 'document' | Rect;
type Axis = 'x' | 'y';
// Placement and positioning types
type Placement = 'top' | 'top-start' | 'top-end' | 'right' | 'right-start' | 'right-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end';
type Strategy = 'absolute' | 'fixed';
type Side = 'top' | 'right' | 'bottom' | 'left';
type Alignment = 'start' | 'end';
// Geometry types
interface Rect {
width: number;
height: number;
x: number;
y: number;
}
interface Coords {
x: number;
y: number;
}
interface Dimensions {
width: number;
height: number;
}
interface ElementRects {
reference: Rect;
floating: Rect;
}
interface SideObject {
top: number;
right: number;
bottom: number;
left: number;
}// Backwards compatibility - will be removed in next major version
function getOverflowAncestors(element: Element): Array<Element>;