# autoPlacement

A visibility optimizer that chooses the placement that has the
most space available automatically.

<div className="flex flex-col gap-4">
  <Chrome
    label="Scroll the container"
    center
    scrollable="y"
    className="h-96"
  >
    <Floating
      middleware={[
        {
          name: 'autoPlacement',
          options: {allowedPlacements: ['top', 'bottom']},
        },
      ]}
    >
      <div className="grid h-8 w-8 place-items-center border-2 border-dashed border-gray-1000" />
    </Floating>
  </Chrome>
</div>

This is useful when you don't know which placement will be best
for the floating element, or don't want to have to explicitly
specify it.

## Usage

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

computePosition(referenceEl, floatingEl, {
  middleware: [autoPlacement()],
});
```

<Notice type="warning" title="Note">
  This is an alternative to `flip(){:js}`, so only one of either can be used.
  See [how they differ here](/docs/autoPlacement#conflict-with-flip).
</Notice>

## Options

These are the options you can pass to `autoPlacement(){:js}`.

```ts
interface Options extends DetectOverflowOptions {
  crossAxis?: boolean;
  alignment?: Alignment | null;
  autoAlignment?: boolean;
  allowedPlacements?: Array<Placement>;
}
```

### crossAxis

default: `false{:js}`

Determines whether a "most space" strategy is also used for the
cross axis (which runs along the alignment of the floating
element). May be desirable when the
`allowedPlacements{:.objectKey}` are all on the same axis.

```js
autoPlacement({
  crossAxis: true,
});
```

### alignment

default: `undefined{:js}`

Without options, `autoPlacement(){:js}` will choose any of the
`Side{:.class}` placements which fit best, i.e. `'top'{:js}`,
`'right'{:js}`, `'bottom'{:js}`, or `'left'{:js}`.

By specifying an alignment, it will choose those aligned
placements.

```js
autoPlacement({
  // top-start, right-start, bottom-start, left-start
  alignment: 'start',
});
```

### autoAlignment

default: `true{:js}`

When `alignment{:.objectKey}` is specified, this describes
whether to automatically choose placements with the opposite
alignment if they fit better.

```js
autoPlacement({
  alignment: 'start',
  // Won't also choose 'end' alignments if those fit better
  autoAlignment: false,
});
```

### allowedPlacements

default: computed subset of `allPlacements{:.const}`

Describes the placements which are allowed to be chosen.

```js
autoPlacement({
  // 'right' and 'left' won't be chosen
  allowedPlacements: ['top', 'bottom'],
});
```

```js
autoPlacement({
  // Only choose these placements
  allowedPlacements: ['top-start', 'bottom-end'],
});
```

### ...detectOverflowOptions

All of [`detectOverflow`](/docs/detectOverflow#options)'s options
can be passed. For instance:

```js
autoPlacement({
  padding: 5, // 0 by default
});
```

### Deriving options from state

You can derive the options from the
[middleware lifecycle state](/docs/middleware#middlewarestate):

```js
autoPlacement((state) => ({
  padding: state.rects.reference.width,
}));
```

## Final placement

The placement returned from the function will let you know which
placement was chosen.

```js
computePosition(referenceEl, floatingEl, {
  middleware: [autoPlacement()],
}).then(({placement}) => {
  console.log(placement); // 'top', 'bottom', 'left' or 'right'
});
```

## Conflict with flip

`flip(){:js}` and `autoPlacement(){:js}` cannot be used together
inside the same middleware array, make sure you choose only one
of them to use.

The reason is they both try to perform work on the placement but
with opposing strategies. Therefore, they will continually try to
change the result or work of the other one, leading to a reset
loop.

- `flip(){:js}` — Uses a fallback "no space" strategy. Ensures
  the preferred placement is kept unless there is no space left.
- `autoPlacement(){:js}` — Uses a primary "most space" strategy.
  Always chooses the placement with the most space available.
