FezVrasta/popper.js

View on GitHub
website/pages/docs/computePosition.mdx

Summary

Maintainability
Test Coverage
<PageCard>

# computePosition

Computes coordinates to position a floating element next to
another element.

<ShowFor packages={['core']}>

```js
import {computePosition} from '@floating-ui/core';
```

</ShowFor>

<ShowFor packages={['dom']}>

```js
import {computePosition} from '@floating-ui/dom';
```

</ShowFor>

<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>

</PageCard>

## Usage

At its most basic, the function accepts two elements:

- **Reference element** — also known as the anchor element, this
  is the element that is being _referred_ to for positioning.
  Often this is a button that triggers a floating popover like a
  tooltip or menu.
- **Floating element** — this is the element that floats next to
  the reference element, remaining anchored to it. This is the
  popover or tooltip itself.

<ShowFor packages={['core', 'react-native']}>

```js
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](/docs/platform#methods).

</ShowFor>

<ShowFor packages={['dom', 'react-dom' ,'react', 'vue']}>

```html
<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:

```css
#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.

</ShowFor>

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']}>

```js /button/1,3#a /tooltip/1,3-4#b
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>

<ShowFor packages={['dom', 'react-dom', 'react', 'vue']}>

```js /button/1,3#a /tooltip/1,3-4#b
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`,
  });
});
```

</ShowFor>

`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.

<ShowFor packages={['dom', 'react-dom', 'react', 'vue']}>

### Initial layout

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:

```css {2-5}
#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.

## Anchoring

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`](/docs/autoUpdate):

```js
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();
```

</ShowFor>

## Options

Passed as a third argument, this is the object to configure the
behavior.

```js
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:

```ts
type Placement =
  | 'top'
  | 'top-start'
  | 'top-end'
  | 'right'
  | 'right-start'
  | 'right-end'
  | 'bottom'
  | 'bottom-start'
  | 'bottom-end'
  | 'left'
  | 'left-start'
  | 'left-end';
```

```js
computePosition(referenceEl, floatingEl, {
  placement: 'bottom-start', // 'bottom' by default
});
```

The `-start{:.string}` and `-end{:.string}` alignments are
[logical](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties)
and will adapt to the writing direction (e.g. RTL) as expected.

<Notice>
  You aren't limited to just these 12 placements though.
  [`offset`](/docs/offset#creating-custom-placements) allows you
  to create _any_ placement.
</Notice>

<ShowFor packages={['dom', 'react-dom', 'react', 'vue']}>

### `strategy{:.key}`

This is the type of CSS position property to use. Two strings are
available:

```ts
type Strategy = 'absolute' | 'fixed';
```

```js
computePosition(referenceEl, floatingEl, {
  strategy: 'fixed', // 'absolute' by default
});
```

Ensure your initial layout matches the strategy:

```css
#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](/docs/misc#clipping).

</ShowFor>

### `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:

#### Placement modifiers

These middleware alter the base placement coordinates.

- [`offset`](/docs/offset) modifies the placement to add distance
  or margin between the reference and floating elements.

- [`inline`](/docs/inline) positions the floating element
  relative to individual client rects rather than the bounding
  box for better precision.

#### Visibility optimizers

These middleware alter the coordinates to ensure the floating
element stays on screen optimally.

- [`shift`](/docs/shift) prevents the floating element from
  overflowing a clipping container by shifting it to stay in
  view.

- [`flip`](/docs/flip) prevents the floating element from
  overflowing a clipping container by flipping it to the opposite
  placement to stay in view.

- [`autoPlacement`](/docs/autoPlacement) automatically chooses a
  placement for you using a "most space" strategy.

- [`size`](/docs/size) resizes the floating element, for example
  so it will not overflow a clipping container, or to match the
  width of the reference element.

#### Data providers

These middleware only provide data and do not alter the
coordinates.

- [`arrow`](/docs/arrow) provides data to position an inner
  element of the floating element such that it is centered to its
  reference element.

- [`hide`](/docs/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.

#### Custom

You can also craft your own custom middleware to extend the
behavior of the library. Read [Middleware](/docs/middleware) to
learn how to create your own.

#### Conditional

Middleware can be called conditionally inside the array inline
for ergonomics:

```ts
// 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:

```js {5-6}
function wrapper(referenceEl, floatingEl, options) {
  return computePosition(referenceEl, floatingEl, {
    ...options,
    middleware: [
      options.enableFlip && flip(),
      options.arrowEl && arrow({element: options.arrowEl}),
    ],
  });
}
```

## Return value

`computePosition(){:js}` returns the following type:

```ts
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.