website/pages/docs/computePosition.mdx
Computes coordinates to position a floating element next to another element.
<ShowFor packages={['core']}>
import {computePosition} from '@floating-ui/core';
<ShowFor packages={['dom']}>
import {computePosition} from '@floating-ui/dom';
<ShowFor packages={['react', 'react-dom', 'react-native', 'vue']}>
<Notice type="warning" title="Non-framework API">
useFloating(){:js} should be used instead with a framework.
If you are using a base package, change the package with the red package
switcher at the top of the page.
</Notice>
</ShowFor>
At its most basic, the function accepts two elements:
<ShowFor packages={['core', 'react-native']}>
const referenceEl = {width: 100, height: 100, x: 50, y: 50};
const floatingEl = {width: 200, height: 200, x: 0, y: 0};
Then, call computePosition(){:js} with them as arguments,
ensuring you pass the required
platform methods.
<ShowFor packages={['dom', 'react-dom' ,'react', 'vue']}>
<button id="button">My reference element</button>
<div id="tooltip">My floating element</div>
First, give the floating element initial CSS styles so that it becomes an absolutely-positioned element that floats on top of the UI with layout ready for being measured:
#tooltip {
/* Float on top of the UI */
position: absolute;
/* Avoid layout interference */
width: max-content;
top: 0;
left: 0;
}
Then, ensuring that these two elements are rendered onto the
document and can be measured, call computePosition(){:js}
with them as arguments.
The first argument is the <WordHighlight id="a">reference element</WordHighlight> to anchor to, and the second argument is the <WordHighlight id="b">floating element</WordHighlight> to be positioned.
<ShowFor packages={['core', 'react-native']}>
import {computePosition} from '@floating-ui/core';
const referenceEl = {width: 100, height: 100, x: 50, y: 50};
const floatingEl = {width: 200, height: 200, x: 0, y: 0};
computePosition(referenceEl, floatingEl, {
platform: {
// See https://floating-ui.com/docs/platform
},
}).then(({x, y}) => {
// Paint the screen.
});
<ShowFor packages={['dom', 'react-dom', 'react', 'vue']}>
import {computePosition} from '@floating-ui/dom';
const button = document.querySelector('#button');
const tooltip = document.querySelector('#tooltip');
computePosition(button, tooltip).then(({x, y}) => {
Object.assign(tooltip.style, {
left: `${x}px`,
top: `${y}px`,
});
});
computePosition(){:js} returns a Promise{:.class} that
resolves with the coordinates that can be used to apply styles to
the floating element.
By default, the floating element will be placed at the bottom center of the reference element.
In order for the floating element to be measured and thus
correctly positioned, it must be rendered onto the DOM and not
hidden when computePosition(){:js} is called. Ensure CSS like
display: none{:sass} is removed prior to calling the function.
<ShowFor packages={['dom', 'react-dom', 'react', 'vue']}>
To ensure positioning works smoothly, the dimensions of the floating element should not change before and after being positioned.
Certain CSS styles must be applied before
computePosition(){:js} is called:
#floating {
position: absolute;
width: max-content;
top: 0;
left: 0;
}
position: absolute{:sass}This makes the element float on top of the UI with intrinsic
dimensions based on the content, instead of acting as a block.
The top{:.key} and left{:.key} coordinates can then take
effect.
width: max-content{:sass} (or a fixed value)top: 0{:sass}left: 0{:sass}These properties prevent the floating element from resizing when it overflows a container, removing layout interference that can cause incorrect measurements.
This lets you place the floating element anywhere in the DOM tree and have it be positioned correctly, regardless of the CSS styles of any ancestor containers.
Since computePosition(){:js} is only a single function call, it
only positions the floating element once.
To ensure it remains anchored to the reference element in a
variety of scenarios, such as when resizing or scrolling, wrap
the calculation in autoUpdate:
import {computePosition, autoUpdate} from '@floating-ui/dom';
// When the floating element is mounted to the DOM:
const cleanup = autoUpdate(referenceEl, floatingEl, () => {
computePosition(referenceEl, floatingEl).then(({x, y}) => {
// ...
});
});
// ...later, when it's removed from the DOM:
cleanup();
Passed as a third argument, this is the object to configure the behavior.
computePosition(referenceEl, floatingEl, {
// options
});
placement{:.key}Where to place the floating element relative to its reference
element. By default, this is 'bottom'{:js}.
12 strings are available:
type Placement =
| 'top'
| 'top-start'
| 'top-end'
| 'right'
| 'right-start'
| 'right-end'
| 'bottom'
| 'bottom-start'
| 'bottom-end'
| 'left'
| 'left-start'
| 'left-end';
computePosition(referenceEl, floatingEl, {
placement: 'bottom-start', // 'bottom' by default
});
The -start{:.string} and -end{:.string} alignments are
logical
and will adapt to the writing direction (e.g. RTL) as expected.
<ShowFor packages={['dom', 'react-dom', 'react', 'vue']}>
strategy{:.key}This is the type of CSS position property to use. Two strings are available:
type Strategy = 'absolute' | 'fixed';
computePosition(referenceEl, floatingEl, {
strategy: 'fixed', // 'absolute' by default
});
Ensure your initial layout matches the strategy:
#tooltip {
position: fixed;
}
These strategies are differentiated as follows:
'absolute'{:js} — the floating element is positioned relative
to its nearest positioned ancestor. With most layouts, this
usually requires the browser to do the least work when updating
the position.'fixed'{:js} — the floating element is positioned relative to
its nearest containing block (usually the viewport). This is
useful when the reference element is also fixed to reduce
jumpiness with positioning while scrolling. It will in many
cases also
"break" the floating element out of a clipping ancestor.middleware{:.key}When you want granular control over how the floating element is
positioned, middleware are used. They read the current
coordinates, optionally alter them, and/or provide data for
rendering. They compose and work together to produce the final
coordinates which you receive as x{:.param} and y{:.param}
parameters.
The following are included in the package:
These middleware alter the base placement coordinates.
offset modifies the placement to add distance
or margin between the reference and floating elements.
inline positions the floating element
relative to individual client rects rather than the bounding
box for better precision.
These middleware alter the coordinates to ensure the floating element stays on screen optimally.
shift prevents the floating element from
overflowing a clipping container by shifting it to stay in
view.
flip prevents the floating element from
overflowing a clipping container by flipping it to the opposite
placement to stay in view.
autoPlacement automatically chooses a
placement for you using a "most space" strategy.
size resizes the floating element, for example
so it will not overflow a clipping container, or to match the
width of the reference element.
These middleware only provide data and do not alter the coordinates.
arrow provides data to position an inner
element of the floating element such that it is centered to its
reference element.
hide provides data to hide the floating element
in applicable situations when it no longer appears attached to
its reference element due to different clipping contexts.
You can also craft your own custom middleware to extend the behavior of the library. Read Middleware to learn how to create your own.
Middleware can be called conditionally inside the array inline for ergonomics:
// The array can accept `false`, `null`, or `undefined`
// inside of it. They get filtered out.
type MiddlewareOption = Array<
Middleware | false | null | undefined
>;
Often this is useful for higher-level wrapper functions to avoid needing the consumer to import middleware themselves:
function wrapper(referenceEl, floatingEl, options) {
return computePosition(referenceEl, floatingEl, {
...options,
middleware: [
options.enableFlip && flip(),
options.arrowEl && arrow({element: options.arrowEl}),
],
});
}
computePosition(){:js} returns the following type:
interface ComputePositionReturn {
x: number;
y: number;
placement: Placement;
strategy: Strategy;
middlewareData: MiddlewareData;
}
x{:.key}The x-coordinate of the floating element.
y{:.key}The y-coordinate of the floating element.
placement{:.key}The final placement of the floating element, which may be different from the initial or preferred one passed in due to middleware modifications. This allows you to know which side the floating element is placed at.
strategy{:.key}The CSS position property to use.
middlewareData{:.key}The data returned by any middleware used.