NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #432 most downloaded on npm
Positioning library for floating elements: tooltips, popovers, dropdowns, and more
Last release 2 months ago
11 Jul 2026
Release timing varies
gaps range from 2 weeks to 6 months
Most releases are documented
notes for 52 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
5 years old
63 releases · first in 2021
One column per quarter.
feat: add 'layoutViewport' string option to rootBoundary . Unlike the visual 'viewport' boundary, it remains stable while pinch-zooming or when a mobi
'layoutViewport' string option to rootBoundary. Unlike the visual 'viewport' boundary, it remains stable while pinch-zooming or when a mobile software keyboard is open, and unlike a manually passed Rect of the documentElement's client size, it accounts for space reserved by scrollbar-gutter: stable.undefined for optional properties with exactOptionalPropertyTypeslayoutShift refresh throttle when the reference moved during an observer refreshscrollbar-gutter: stable both-edges reserved spacegetClientRects when a virtual element without a getClientRects method is used with the inline() middleware@floating-ui/core@1.8.0, @floating-ui/utils@0.2.12'layoutViewport' string option to rootBoundary. Unlike the visual 'viewport' boundary, it remains stable while pinch-zooming or when a mobile software keyboard is open, and unlike a manually passed Rect of the documentElement's client size, it accounts for space reserved by scrollbar-gutter: stable.undefined for optional properties with exactOptionalPropertyTypes@floating-ui/utils@0.2.12perf: bundle and runtime improvements
@floating-ui/utils@0.2.11fix(getViewportRect): account for space left by scrollbar-gutter: stable
scrollbar-gutter: stableUpdate dependencies: @floating-ui/core@1.7.3
@floating-ui/core@1.7.3perf: reduce memory allocations
@floating-ui/utils@0.2.10, @floating-ui/core@1.7.2Update dependencies: @floating-ui/core@1.7.1
@floating-ui/core@1.7.1crossAxis: 'alignment'feat(flip): add "alignment" string value for crossAxis option. This value determines if cross axis overflow checking is restricted to the alignment of
"alignment" string value for crossAxis option. This value determines if cross axis overflow checking is restricted to the alignment of the placement only. This prevents fallbackPlacements/fallbackAxisSideDirection from too eagerly changing to the perpendicular side (thereby preferring shift() if overflow is detected along the cross axis, even if shift() is placed after flip() in the middleware array).@floating-ui/core@1.7.0Update dependencies: @floating-ui/utils@0.2.9
@floating-ui/utils@0.2.9frameElement is readable to avoid errors in Safari and MSEdge with cross-origin iframes@floating-ui/utils@0.2.6fix(size): fill viewport along an axis if shift is enabled on that axis
@floating-ui/utils@0.2.8Update dependencies: @floating-ui/utils@0.2.7
@floating-ui/utils@0.2.7@floating-ui/utils@0.2.4Update dependencies: @floating-ui/utils@0.2.6
@floating-ui/utils@0.2.6getClientRects() method to VirtualElement@floating-ui/utils@0.2.3Update dependencies: @floating-ui/utils@0.2.5
@floating-ui/utils@0.2.5<svg> arrow element offsetParent. Fixes arrow positioning when styling an inner element of the floating element with a border.clippingAncestors collision boundary for top layer elementsOffsetOptions aliasUpdate dependencies: @floating-ui/utils@0.2.4
@floating-ui/utils@0.2.4DOMRect typesfix(flip): adjust bestFit algorithm to only use initialPlacement or y side axis with fallbackAxisSideDirection
bestFit algorithm to only use initialPlacement or y side axis with fallbackAxisSideDirection@floating-ui/utils@0.2.3offsetParent iframe. Fixes issue with positioning in nested iframes, such as the following:<html>
<iframe>
<div>floating</div>
<iframe>
<div>reference</div>
</iframe>
</iframe>
</html>
fix(size): correctly constrain floating element to avoid overflowing outside viewport with shift({crossAxis: true})
shift({crossAxis: true})absolute strategyfix: avoid spreading rects to support DOMRect types
DOMRect typesgetContainingBlock call for non-top layer elementsfix: handle CSS :top-layer elements inside containing blocks. It's no longer necessary to implement the middleware workaround outlined in .
:top-layer elements inside containing blocks. It's no longer
necessary to implement the middleware workaround outlined in
https://github.com/floating-ui/floating-ui/issues/1842#issuecomment-1872653245.@floating-ui/core@1.6.04c04669: chore: export .d.mts types, solves #2472
23f32f5d: fix(types): avoid ts 4.2+ syntax
88bf9768: fix(offset): avoid doubling calculation on same placement reset when arrow changes alignment of floating element
arrow changes alignment of floating elementmoduleResolution: "NodeNext" (#2473)d7e07fba: feat(arrow): add alignmentOffset data
alignmentOffset data@floating-ui/utils package (@floating-ui/utils/dom import) (#2449)0ef68ffa: fix(arrow): perform a reset if internal shifting is performed
0ef68ffa: fix(arrow): perform a reset if internal shifting is performed
This allows shift() to continue taking action when the arrow's internal
shifting of the floating element is performed (preventing potential
overflow/clipping of the floating element in certain scenarios), while still
allowing the arrow to point toward the reference when it is small if possible.
Updated dependencies [a6c72f50]
IntersectionObserver threshold (#2390)fix(types): resolution when using moduleResolution: "NodeNext"
moduleResolution: "NodeNext" (#2473)Split utils into @floating-ui/utils package
@floating-ui/utils package (#2449)feat(autoUpdate): add layoutShift option (true by default) to detect when the reference element moves on the screen. Thank you to @samthor for the technique using IntersectionObserver. (#2373)
If you were using animationFrame: true for this purpose, you can now disable the option and use the defaults for layout shift checks. That option should now only be used if you need the floating element to stay anchored either during an animation using transform of the reference element, or for nested portaled floating elements (if necessary).
fix: loop in tests with mocked Node (#2383)
fix(autoUpdate): animationFrame: true preventing updates if reference element is fixed (#2373)
fix(arrow): report correct centerOffset value when internal shifting is active
centerOffset value when internal shifting is active (#2382)feat: allow function types for all middleware options, including detectOverflow, to allow derivation from state
feat: allow function types for all middleware options, including detectOverflow, to allow derivation from state (#2359)
// Options
shift({mainAxis: true});
// Derived from state
shift((state) => ({mainAxis: state.rects.reference.width > 10}));
refactor(types): exported middleware Options types (#2359)
Options objects now include DetectOverflowOptions in them, and are auto-Partial where necessary. The types do not include the function type in them.feat: allow function types for all middleware options, including detectOverflow, to allow derivation from state (#2359)
// Options
shift({mainAxis: true});
// Derived from state
shift((state) => ({mainAxis: state.rects.reference.width > 10}));
refactor(types): exported middleware Options types (#2359)
Options objects now include DetectOverflowOptions in them, and are auto-Partial where necessary. The types do not include the function type in them.padding option value does not cause incorrect centering (#2360)platform object to be passed to the useFloating hook (#2176)fix(types): re-export middleware options types (#2175)
fix(types): add @deprecation notice to non-ref nested element setters (#2175)
fix(getClippingRect): incorrect calculation of position: fixed clipping ancestors
position: fixed clipping ancestors (#2280)available size if floating element resized using a center-aligned placement with shift() in use (#2281)fix: remove DEV warnings (process.env)
process.env) (#2251)fix: don't skip initial ResizeObserver callback update in autoUpdate (#2232)
This runs two updates on mount instead of one when elementResize is enabled. When dealing with frameworks that use inside-out (down-up) initialization of effects/rendering, like React, children are positioned before their parent positioned which meant they were positioned relative to the (0, 0) coordinates, which is incorrect. This problem only presents itself when the child and parent both try to position themselves at the same time on mount — for example, opening a menu and its submenu simultaneously.
By not skipping this update, this issue isn't present since children reposition themselves after their parents have been positioned.
fix(inline): correct merging of rects by line
<svg> arrows with CSS sizes instead of getBoundingClientRect() to avoid reading transformations (#2223)fix(inline): merge rects on the same line (y coord)
window for SVG elements (#2198)fix(arrow): correctly take into account floating element border for arrows
border for <svg> arrows (#2195)fix(getClippingRect): prevent fixed ancestors from creating a clipping ancestor
fix(getClippingRect): prevent fixed ancestors from creating a clipping ancestor (#2170)
fix(types): re-export middleware options types (#2175)
MiddlewareArguments in favor of MiddlewareState type (#2175)feat(platform): add ability to polyfill offsetParent access (in a pure way) to fix a platform gap where the incorrect value is returned inside shadow
feat(platform): add ability to polyfill offsetParent access (in a pure way) to fix a platform gap where the incorrect value is returned inside shadow DOM. (#2160)
This was previously done internally a while ago (1.0.1) but reportedly causes a performance issue in certain scenarios, meaning it cannot be a default. This allows the polyfill to be conditionally enabled by libraries. The polyfill and its usage is available here, which ideally would be made into its own package (that can be iterated on and potentially improved perf-wise).
feat(detectOverflow): accept virtual Rect boundaries (#2161)
platform object now has all methods non-optional with Required<Platform> (#2166)feat(autoPlacement): crossAxis option (#2159)
By default, aligned placements like top-start/top-end use a "fallback" strategy for the crossAxis to ensure different axes' placements can be chosen, and to keep the preferred alignment as much as possible.
However, if you only have placements along one axis you can now use a "most space" strategy for the alignment as well, e.g.:
autoPlacement({
allowedPlacements: [
'top-start',
'top-end',
'bottom-start',
'bottom-end'
],
crossAxis: true,
});
feat(detectOverflow): accept virtual Rect boundaries (#2161)
fix(size): consider case where shift() is in the middleware array before size() for center aligned placements (#2163)
fix(autoPlacement): prevent resetting placement unexpectedly to opposite alignment when it overflows on all sides (#2159)
fix(flip): when no placements fit, but before fallbackStrategy phase, if multiple placements fit on the mainAxis of overflow, choose the placement that fits best on the main crossAxis side of overflow (#2163)
fix(autoPlacement): general algorithm improvements (#2159)
fix(size): general algorithm improvements (#2163)
feat: add element setters to refs object (#2101)
const {refs} = useFloating();
<div ref={refs.setReference} />
<div ref={refs.setFloating} />
These replace the reference and floating callback refs (which are now aliases) by being more explicit and less confusing regarding how refs are updated.
The refs object contains:
{
reference: MutableRefObject,
floating: MutableRefObject,
setReference: (node) => void,
setFloating: (node) => void,
}
feat: return elements object from hook (#2101)
If you need to read the elements during render, where refs are not suitable, these contain the elements rather than refs.
fix: ensure MaybeReadonlyRefOrGetter works in earlier versions of Vue
MaybeReadonlyRefOrGetter works in earlier versions of VuemainAxis overflow check first once in fallback phase (#2151)fix(types): allow SVGElement as the arrow element (#2146)
fix(arrow): re-allow SVGElements to be measured (#2146)
fix: re-allow unstable ref callbacks (prevent infinite loop) (#2087)
Since v1.0.0 you didn't need to memoize the callback ref (although is recommended), but in v1.1.0 this caused an infinite loop again:
ref={node => floating(node)}
perf: optimize calling floating and reference callback refs directly in render (#2087)
The docs recommended to use effects to synchronize external elements, but now there's an optimization that allows you to call either during render without needing an effect:
function App({externalNode}) {
const {reference} = useFloating();
// Works and is optimized, no effect needed
reference(externalNode);
}
feat: support MaybeReadonlyRefOrGetter in useFloating
MaybeReadonlyRefOrGetter in useFloating@floating-ui/utils@0.2.4feat(flip): fallbackAxisSideDirection option (#2082)
This option adds the ability to compute placements on the opposite axis of the preferred placement without needing to use an explicit fallbackPlacements list, meaning you no longer need to manage a custom map of fallbackPlacements and instead use this option to leverage automatic computing of the array.
This option determines whether to allow fallback to the opposite axis if no placements along the preferred placement axis fit, and if so, which side direction along that axis to choose. If necessary, it will fallback to the other direction.
'none' signals that no fallback to the opposite axis should take place. (default)'start' represents 'top' or 'left'.'end' represents 'bottom' or 'right'.Note: In RTL writing direction, the x-axis directions are reversed.
For instance, by default, if the initial placement is set to 'right', then the placements to try (in order) are:
['right', 'left']
On a narrow viewport, it's possible or even likely that neither of these will fit.
By specifying a string other than 'none', you allow placements along the opposite axis of the initial placement to be tried. The direction determines which side of placement is tried first:
flip({
fallbackAxisSideDirection: 'start',
});
The above results in: ['right', 'left', 'top', 'bottom'].
flip({
fallbackAxisSideDirection: 'end',
});
The above results in: ['right', 'left', 'bottom', 'top'].
As an example, if you'd like a tooltip that has a placement of 'right' to be placed on top on mobile (assuming it doesn't fit), then you'd use 'start'. For an interactive popover, you likely want to use 'end' so it's placed on the bottom, closer to the user's fingers.
shiftIf shift() is in use in the middleware array, you may desire to disable crossAxis overflow checking, which will allow shift() to perform its work without falling back to the opposite axis (therefore preserving the original axis as best as possible):
const middleware = [
flip({
fallbackAxisSideDirection: 'start',
crossAxis: false,
}),
shift(),
];
This will depend on the desired positioning you want to achieve, e.g. if the placement has an explicit alignment specified or not.
feat: add open option and isPositioned property to wait for the position to be ready. (#2001)
isPositioned allows you to call .scrollIntoView() or .focus() on an element in an effect without causing unwanted scrolling.
const {isPositioned} = useFloating();
This works identically to x === null, but now has the ability to also reset if it doesn't get unmounted based on some state:
const [open, setOpen] = useState(false);
const {isPositioned} = useFloating({
// `isPositioned` is synchronized to this state/value, but
// when it changes to `true`, it will wait for the position,
// unlike when checking `open` directly.
open
});
React.useLayoutEffect(() => {
if (isPositioned) {
element.focus();
element.scrollIntoView();
}
}, [isPositioned]);
This means it will also work if the reference element moved from the first position after the floating element had been positioned for the first time, unlike x === null, making it as reliable as the rAF technique.
For now, null remains as the original value of x and y only for SSR purposes, where the floating element is open already without a client interaction required, which can help with unmounting animations, since isPositioned doesn't wait.
<div
style={{
position: strategy,
top: y ?? 0,
left: x ?? 0,
visibility: x === null ? 'hidden' : 'visible',
}}
/>
fix: support cross-document anchoring, where if floating element is in a higher-level window than the reference element, the positioning takes this into account (i.e. reference element is inside an iframe, but the floating element isn't) (#2043)
Bumping minor version because if you were adding external code/custom middleware to add support yourself, it will break with this update as it's no longer necessary.
refactor(getScale): handle unknowns (#2054)
fix(getDimensions): use computed width/height if possible (#2056)
If using box-sizing: border-box (recommended default by most CSS resets, and this lib), then the floating rect will now always contain fractional values. When using size to set the width of the floating element, it will no longer be truncated unexpectedly (e.g. adding ... ellipsis overflow).
fix(isOverflowElement): check for overflow: clip value (#2070)
Update dependencies: @floating-ui/dom@1.6.0
@floating-ui/dom@1.6.0fix(hide): return options on middleware object (#2058)
React would previously not update stateful options, either via re-renders or Fast Refresh
fix(arrow): only add internal shifting under stricter conditions (#2044)
This prevents the arrow from getting stuck pointing at the center of the reference when padding is specified in most cases, counteracting shift() when it should take precedence, while maintaining the desired behavior for #1496.
fix(autoPlacement): preserve passed allowedPlacements when desired (#2073)
Previously, allowed placements got filtered out if they didn't match the alignment specified. By default this was null, so if you passed aligned placements in the list, they got unexpectedly filtered out. Now, they are respected:
autoPlacement({
// works as expected
allowedPlacements: ['top-start', 'bottom-start']
});
autoPlacement({
alignment: null,
// only 'bottom' is actually allowed
allowedPlacements: ['top-start', 'bottom-start', 'bottom']
});
fix: additional cases where clippingAncestors would return invalid elements (#1956)
fix: rewrite logic to detect clipping element ancestors (#1959)
fix(isContainingBlock): check for backdrop-filter (#1959)
fix: support falsy values in middleware option for conditionals (#1954)
de70c04: fix: change isComponentPublicInstance implementation
isComponentPublicInstance implementationVirtualElement's contextElement if present (#1925)4c04669: chore: export .d.mts types, solves #2472
fix(detectOverflow): pass correct fallback rect (#2000)
If platform.convertOffsetParentRelativeRectToViewportRelativeRect was not available, then the correct rect was not passed. So a custom platform without that method actually did need it (even though it's optional).
fix: do not treat elements with display: inline or display: contents as overflow ancestors (#1847)
fix(autoUpdate): retain ancestorResize option when enabling animationFrame option (#1915)
fix(isContainingBlock): position: fixed positioning when ancestor has contain: paint|layout|strict|content (plus multiple values) (#1922)
fix: clippingAncestors rect detection when reference ancestor has position: absolute, allowing it to escape a clipping ancestor (e.g. commonly encountered with hide() middleware) (#1923)
fix(isContainingBlock): position: fixed positioning when ancestor has multiple will-change values when one of them will create a containing block (#1922)
fix: widen type for ArrowOptions.element
fix: widen type for ArrowOptions.element (#2450)
Allows MaybeElement<Element> instead of MaybeElement<HTMLElement> to improve interaction with Vue's Function Refs
fix: avoid arrow re-export collision (#2450)
fix: if the reference or floating elements are falsy/null when computePosition() is called there's an unhelpful error about getComputedStyle; there is now a proper error message in dev mode. (#1954)
fix: the middleware array can now contain false, null, or undefined values. This enables you to pass conditional middleware inline without needing a verbose spread ...(cond ? [m()] : []) or separate statements like .push() — at least for TypeScript, as you could already filter it manually externally. (#1954)
middleware: [
shouldFlip && flip(),
arrowElement && arrow({ element: arrowElement }),
]
perf: revert custom composedOffsetParent polyfill (#1894)
Unfortunately, the platform provides no composedOffsetParent() method and this internal polyfill was causing a performance degradation. As a result, it is now opt-in.
Ideally, the DOM layout where the issue arises should be avoided to begin with. However, if it can't be avoided, the default platform object is now exported so you can spread in all the other methods then write your own single getOffsetParent hook that has the polyfill. You might want to add your own custom flags to turn it on/off when it's considered acceptable in a given scenario perf-wise.
fix: package.json dependency metadata
middleware option for conditionals (#1954)Shadow DOM fixes
fix: incorrect position when starting offset parent element is nested inside shadow DOM (#1827)
fix: add composedOffsetParent internal polyfill for shadow DOM offsetParents (#1835)
SideObject for detectOverflow padding (#1846)Default x and y coordinates to 0 instead of null
Default x and y coordinates to 0 instead of null (#2300)
isPositioned lets you know if the floating element has been positioned.
feat: floatingStyles object (#2300)
Pre-configured positioning styles for the majority of cases:
const {floatingStyles} = useFloating(reference, floating);
<div ref="floating" :style="floatingStyles" />
@floating-ui/core bumped to 1.0.0 (#1796)
UMD package files now have .umd in the filename (#1796)
fix: allow unstable inline ref callbacks (#1796)
fix: check name for middleware array comparisons (#1796)
use-isomorphic-layout-effect from installed deps (#1796)limitShift offset function option now gets whole MiddlewareArguments object spread in to match other APIs (#1796)apply function now has await before it to allow async updates (#1796)TS typedefs are now generated as "strict"
TS typedefs are now generated as "strict" (#1735)
fix: add safeguard return to bail out of positioning after 50 reset requests, preventing any infinite loops, even if more resets are requested. In DEV mode, the error about the positioning loop is now just a warning. (#1742)
TS typedefs are now generated as "strict"
TS typedefs are now generated as "strict"
feat: inner middleware — the floating element is anchored such that an inner element inside of it sits on top of/is anchored to the reference element.
feat: inner middleware — the floating element is anchored such that an inner element inside of it sits on top of/is anchored to the reference element. (#1758)
This works along the y-axis and simulaneously limits the max-height of the floating element.
feat: useInnerOffset interaction hook — allows the height of the floating element to expand on wheel event by changing the offset that inner uses to anchor the inner element (#1758)
FloatingFocusManager. useListNavgation and useDismiss no longer return focus, bypassing issues with unmounting animations. (#1765)fix(useDismiss): outsidePointerDown now uses real pointerdown instead of mousedown (#1765)
Before it required an "intentional" dismiss on touch devices, but now, the user can dismiss while attempting to scroll away
fix(useHover): prevent SVG reference element from failing to apply pointer-events auto styles (#1794)
fix(useClick): pointerDown now uses mousedown instead of pointerdown. This reduces unintentional clicks while touching the screen to scroll, or focus being moved to focusable items inside a floating element unintentionally when tapping the reference element. (#1765)
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
fix: avoid spreading rects to support DOMRect types
DOMRect types180d1ad: fix: devtools controller emits event once the selected element is removed
3d0368e: feat!: introduce serialized data as an array
/react pathopen option and isPositioned return value (#2083)28659c4d: refactor: move react utils to @floating-ui/react/utils
3d8b9c65: fix(getOverflowAncestors): handle traverseIframes correctly when there are clipping ancestors in the inner frame
a6c72f50: fix(getOverflowAncestors): avoid traversing into iframes for clipping detection
cb48d956: fix(dom): traverse into iframe parents when finding overflow ancestors
Your coding agent can read these notes before it upgrades. Set up the MCP server →