Specialized middleware for complex positioning scenarios including auto-placement, arrow positioning, size constraints, visibility detection, and inline element handling.
Optimizes visibility by automatically choosing the placement that has the most space available. Alternative to flip when you want to automatically find the best placement.
/**
* Optimizes the visibility of the floating element by choosing the placement
* that has the most space available automatically, without needing to specify
* a preferred placement.
*
* @param options - Auto placement configuration
* @returns Middleware object
*/
function autoPlacement(options?: AutoPlacementOptions): Middleware;
interface AutoPlacementOptions extends DetectOverflowOptions {
/** Whether to check cross axis for most space */
crossAxis?: boolean;
/** Prefer placements with particular alignment */
alignment?: Alignment | null;
/** Whether to choose opposite alignments if preferred doesn't fit */
autoAlignment?: boolean;
/** Which placements are allowed to be chosen */
allowedPlacements?: Array<Placement>;
}Usage Examples:
import { computePosition, autoPlacement } from "@floating-ui/core";
// Automatic placement selection
await computePosition(reference, floating, {
middleware: [autoPlacement()], // Chooses best available placement
platform: domPlatform
});
// Prefer specific alignment
await computePosition(reference, floating, {
middleware: [
autoPlacement({
alignment: "start", // Prefer start-aligned placements
autoAlignment: true // Allow end-aligned if start doesn't fit
})
],
platform: domPlatform
});
// Limit allowed placements
await computePosition(reference, floating, {
middleware: [
autoPlacement({
allowedPlacements: ["top", "bottom", "top-start", "bottom-start"]
})
],
platform: domPlatform
});Provides data to position an inner arrow element so it appears centered relative to the reference element.
/**
* Provides data to position an inner element of the floating element so that it
* appears centered to the reference element.
*
* @param options - Arrow configuration
* @returns Middleware object
*/
function arrow(options: ArrowOptions): Middleware;
interface ArrowOptions {
/** The arrow element to be positioned */
element: any;
/** Padding between arrow and floating element edges */
padding?: Padding;
}Usage Examples:
import { computePosition, arrow, offset, flip } from "@floating-ui/core";
// Basic arrow positioning
const arrowElement = document.querySelector('.arrow');
const { x, y, placement, middlewareData } = await computePosition(
reference,
floating,
{
placement: "top",
middleware: [
offset(8),
flip(),
arrow({ element: arrowElement })
],
platform: domPlatform
}
);
// Position the floating element
Object.assign(floating.style, {
left: `${x}px`,
top: `${y}px`,
});
// Position the arrow using middleware data
const arrowData = middlewareData.arrow;
if (arrowData) {
const side = placement.split('-')[0];
const arrowSide = {
top: 'bottom',
right: 'left',
bottom: 'top',
left: 'right'
}[side];
Object.assign(arrowElement.style, {
left: arrowData.x != null ? `${arrowData.x}px` : '',
top: arrowData.y != null ? `${arrowData.y}px` : '',
[arrowSide]: `-4px` // Half of arrow size
});
}Provides data to change the size of the floating element, for instance to prevent it from overflowing clipping boundaries or to match the reference element width.
/**
* Provides data that allows you to change the size of the floating element —
* for instance, prevent it from overflowing the clipping boundary or match the
* width of the reference element.
*
* @param options - Size configuration
* @returns Middleware object
*/
function size(options?: SizeOptions): Middleware;
interface SizeOptions extends DetectOverflowOptions {
/** Function to apply size changes to the floating element */
apply?(args: MiddlewareState & {
availableWidth: number;
availableHeight: number;
}): void | Promise<void>;
}Usage Examples:
import { computePosition, size, flip } from "@floating-ui/core";
// Prevent overflow by constraining size
await computePosition(reference, floating, {
middleware: [
size({
apply({ availableWidth, availableHeight, elements }) {
// Constrain to available space
Object.assign(elements.floating.style, {
maxWidth: `${availableWidth}px`,
maxHeight: `${availableHeight}px`,
});
},
}),
flip()
],
platform: domPlatform
});
// Match reference width
await computePosition(reference, floating, {
middleware: [
size({
apply({ rects, elements }) {
// Match reference element width
Object.assign(elements.floating.style, {
width: `${rects.reference.width}px`,
});
},
})
],
platform: domPlatform
});Provides data to hide the floating element when it's not in the same clipping context as the reference element or has escaped the clipping boundary.
/**
* Provides data to hide the floating element in applicable situations, such as
* when it is not in the same clipping context as the reference element.
*
* @param options - Hide configuration
* @returns Middleware object
*/
function hide(options?: HideOptions): Middleware;
interface HideOptions extends DetectOverflowOptions {
/** Strategy for determining when to hide */
strategy?: "referenceHidden" | "escaped";
}Usage Examples:
import { computePosition, hide, offset, flip } from "@floating-ui/core";
// Hide when reference is not visible
const { middlewareData } = await computePosition(reference, floating, {
middleware: [
offset(10),
flip(),
hide({ strategy: "referenceHidden" })
],
platform: domPlatform
});
// Apply visibility based on hide data
const hideData = middlewareData.hide;
if (hideData?.referenceHidden) {
Object.assign(floating.style, {
visibility: "hidden",
});
}
// Hide when floating element escapes boundaries
const { middlewareData } = await computePosition(reference, floating, {
middleware: [
hide({ strategy: "escaped" })
],
platform: domPlatform
});
const hideData = middlewareData.hide;
if (hideData?.escaped) {
Object.assign(floating.style, {
visibility: "hidden",
});
}Provides improved positioning for inline reference elements that span multiple lines, such as hyperlinks or range selections.
/**
* Provides improved positioning for inline reference elements that can span
* over multiple lines, such as hyperlinks or range selections.
*
* @param options - Inline configuration
* @returns Middleware object
*/
function inline(options?: InlineOptions): Middleware;
interface InlineOptions {
/** Viewport-relative x coordinate to choose a ClientRect */
x?: number;
/** Viewport-relative y coordinate to choose a ClientRect */
y?: number;
/** Padding around disjoined rect when choosing it */
padding?: Padding;
}Usage Examples:
import { computePosition, inline, flip, shift } from "@floating-ui/core";
// Basic inline positioning
await computePosition(textSelection, tooltip, {
middleware: [
inline(),
flip(),
shift()
],
platform: domPlatform
});
// Inline with cursor position
const handleMouseEnter = async (event) => {
const { x, y } = await computePosition(linkElement, tooltip, {
middleware: [
inline({
x: event.clientX,
y: event.clientY,
padding: 4
}),
flip(),
shift()
],
platform: domPlatform
});
Object.assign(tooltip.style, {
left: `${x}px`,
top: `${y}px`,
});
};import {
computePosition,
offset,
flip,
shift,
arrow,
hide,
autoPlacement
} from "@floating-ui/core";
const createAdvancedTooltip = async (reference, floating, arrowElement) => {
const { x, y, placement, middlewareData } = await computePosition(
reference,
floating,
{
placement: "top",
middleware: [
offset(8),
flip({
fallbackAxisSideDirection: "start",
fallbackStrategy: "bestFit"
}),
shift({ padding: 8 }),
arrow({
element: arrowElement,
padding: 4
}),
hide({ strategy: "referenceHidden" })
],
platform: domPlatform
}
);
// Position floating element
Object.assign(floating.style, {
left: `${x}px`,
top: `${y}px`,
});
// Position arrow
const arrowData = middlewareData.arrow;
if (arrowData) {
const side = placement.split('-')[0];
const staticSide = {
top: 'bottom',
right: 'left',
bottom: 'top',
left: 'right'
}[side];
Object.assign(arrowElement.style, {
left: arrowData.x != null ? `${arrowData.x}px` : '',
top: arrowData.y != null ? `${arrowData.y}px` : '',
right: '',
bottom: '',
[staticSide]: '-4px',
});
}
// Handle visibility
const hideData = middlewareData.hide;
if (hideData?.referenceHidden) {
Object.assign(floating.style, {
visibility: 'hidden',
});
}
};import { computePosition, size, autoPlacement, shift } from "@floating-ui/core";
const createResponsiveDropdown = async (trigger, dropdown) => {
const { x, y, placement } = await computePosition(trigger, dropdown, {
middleware: [
autoPlacement({
allowedPlacements: ["bottom-start", "bottom-end", "top-start", "top-end"],
crossAxis: true
}),
size({
apply({ availableWidth, availableHeight, elements, rects }) {
// Responsive sizing logic
const maxWidth = Math.min(availableWidth, 400);
const maxHeight = Math.min(availableHeight, 300);
Object.assign(elements.floating.style, {
maxWidth: `${maxWidth}px`,
maxHeight: `${maxHeight}px`,
width: rects.reference.width > 200
? `${rects.reference.width}px`
: 'auto'
});
},
}),
shift({ padding: 16 })
],
platform: domPlatform
});
Object.assign(dropdown.style, {
left: `${x}px`,
top: `${y}px`,
});
};