# shift

A visibility optimizer that shifts the floating element along the
specified axes in order to keep it in view.

<Chrome label="Scroll horizontally" center scrollable="x">
  <Floating
    content="A floating element that shifts along the x-axis"
    middleware={[{name: 'shift'}]}
    portaled
    bounded
  >
    <div className="m-4 grid h-10 w-10 place-items-center border-2 border-dashed border-gray-1000" />
  </Floating>
</Chrome>

This is useful for preventing overflow while maintaining the
desired placement as best as possible.

## Usage

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

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

## Options

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

```ts
interface Options extends DetectOverflowOptions {
  mainAxis?: boolean;
  crossAxis?: boolean;
  limiter?: {
    fn: (state: MiddlewareState) => Coords;
    options?: any;
  };
}
```

### mainAxis

default: `true{:js}`

This is the main axis in which shifting is applied.

- `x`-axis for `'top'{:js}` and `'bottom'{:js}` placements
- `y`-axis for `'left'{:js}` and `'right'{:js}` placements

```js
shift({
  mainAxis: false,
});
```

<Chrome label="Scroll horizontally" center scrollable="x">
  <Floating
    content="A floating element that does not shift along the x-axis"
    middleware={[{name: 'shift', options: {mainAxis: false}}]}
  >
    <div className="m-4 grid h-10 w-10 place-items-center border-2 border-dashed border-gray-1000" />
  </Floating>
</Chrome>

### crossAxis

default: `false{:js}`

This is the cross axis in which shifting is applied, the opposite
axis of `mainAxis{:.objectKey}`.

Enabling this can lead to the floating element **overlapping**
the reference element, which may not be desired and is often
replaced by the `flip(){:js}` middleware.

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

<Chrome label="Scroll down" center scrollable="y">
  <Floating
    placement="top"
    content="I can overlap my reference element"
    middleware={[
      {
        name: 'shift',
        options: {
          crossAxis: true,
          rootBoundary: 'document',
        },
      },
    ]}
    portaled
    bounded
  >
    <div className="m-4 grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000" />
  </Floating>
</Chrome>

### limiter

default: no-op

This accepts a function that **limits** the shifting done, in
order to prevent detachment or "overly-eager" behavior. The
behavior is to stop shifting once the opposite edges of the
elements are aligned.

```js
import {shift, limitShift} from '@floating-ui/dom';

shift({
  limiter: limitShift(),
});
```

This function itself takes options.

#### limitShift.mainAxis

default: `true{:js}`

Whether to apply limiting on the main axis.

```js
shift({
  limiter: limitShift({
    mainAxis: false,
  }),
});
```

#### limitShift.crossAxis

default: `true{:js}`

Whether to apply limiting on the cross axis.

```js
shift({
  limiter: limitShift({
    crossAxis: false,
  }),
});
```

#### limitShift.offset

default: `0{:js}`

This will offset when the limiting starts. A positive number will
start limiting earlier, while negative later.

```js
shift({
  limiter: limitShift({
    // Start limiting 5px earlier
    offset: 5,
  }),
});
```

This can also take a function, which provides the
`Rect{:.class}`s of each element to read their dimensions:

```js
shift({
  limiter: limitShift({
    // Start limiting by the reference's width earlier
    offset: ({rects, placement}) => rects.reference.width,
  }),
});
```

You may also pass an object to configure both axes:

```js
shift({
  limiter: limitShift({
    // object
    offset: {
      mainAxis: 10,
      crossAxis: 5,
    },
    // or a function which returns one
    offset: ({rects, placement}) => ({
      mainAxis: rects.reference.height,
      crossAxis: rects.floating.width,
    }),
  }),
});
```

### ...detectOverflowOptions

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

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

If you find the padding does not get applied on the right side,
see [Handling large content](/docs/misc#handling-large-content).

### Deriving options from state

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

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

## Data

The following data is available in `middlewareData.shift{:js}`:

```js
interface Data {
  x: number;
  y: number;
}
```

`x{:.objectKey}` and `y{:.objectKey}` represent how much the
floating element has been shifted along that axis. The values are
offsets, and therefore can be negative.
