# offset

A placement modifier that translates the floating element along
the specified axes.

<Chrome center className="pt-16 pb-24">
  <div className="flex gap-4">
    <Floating middleware={[{name: 'offset', options: 0}]}>
      <div className="mx-auto grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000">
        0px
      </div>
    </Floating>
    <Floating middleware={[{name: 'offset', options: 10}]}>
      <div className="mx-auto grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000">
        10px
      </div>
    </Floating>
  </div>
</Chrome>

This is useful for adding distance between the reference and
floating element, or for creating
[custom placements](/docs/offset#creating-custom-placements).

## Usage

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

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

The value(s) passed are
[logical](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties),
meaning their effect on the physical result is dependent on the
placement, writing direction (e.g. RTL), or alignment.

## Order

`offset(){:js}` should generally be placed at the beginning of
your middleware array.

## Options

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

```ts
type Options =
  | number
  | {
      mainAxis?: number;
      crossAxis?: number;
      alignmentAxis?: number | null;
    };
```

A number represents the distance (gutter or margin) between the
floating element and the reference element. This is shorthand for
`mainAxis{:.objectKey}`.

```js
offset(10);
```

An object can also be passed, which enables you to individually
configure each axis.

### mainAxis

default: `0{:js}`

The axis that runs along the side of the floating element.
Represents the distance (gutter or margin) between the floating
element and the reference element.

```js
offset({
  mainAxis: 10,
});
```

Here's how it looks on the four sides:

<Chrome center className="pt-16 pb-24" tall>
  <div className="mt-4 flex flex-col gap-4 md:flex-row">
    <Floating
      placement="top"
      middleware={[
        {
          name: 'offset',
          options: 10,
        },
      ]}
    >
      <div className="mx-auto grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000">
        top
      </div>
    </Floating>
    <Floating
      placement="bottom"
      middleware={[
        {
          name: 'offset',
          options: 10,
        },
      ]}
    >
      <div className="mx-auto grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000">
        bottom
      </div>
    </Floating>
  </div>
  <div className="flex flex-col gap-4 md:flex-row">
    <Floating
      placement="left"
      middleware={[
        {
          name: 'offset',
          options: 10,
        },
      ]}
    >
      <div className="mx-auto grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000">
        left
      </div>
    </Floating>
    <Floating
      placement="right"
      middleware={[
        {
          name: 'offset',
          options: 10,
        },
      ]}
    >
      <div className="mx-auto grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000">
        right
      </div>
    </Floating>
  </div>
</Chrome>

### crossAxis

default: `0{:js}`

The axis that runs along the alignment of the floating element.
Represents the skidding between the floating element and the
reference element.

```js
offset({
  crossAxis: 20,
});
```

Here's how it looks on the four sides:

<Chrome center className="pt-16 pb-24" tall>
  <div className="mt-4 flex flex-col gap-4 md:flex-row">
    <Floating
      placement="top"
      middleware={[
        {
          name: 'offset',
          options: {crossAxis: 20},
        },
      ]}
    >
      <div className="mx-auto grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000">
        top
      </div>
    </Floating>
    <Floating
      placement="bottom"
      middleware={[
        {
          name: 'offset',
          options: {crossAxis: 20},
        },
      ]}
    >
      <div className="mx-auto grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000">
        bottom
      </div>
    </Floating>
  </div>
  <div className="flex flex-col gap-4 md:flex-row">
    <Floating
      placement="left"
      middleware={[
        {
          name: 'offset',
          options: {crossAxis: 20},
        },
      ]}
    >
      <div className="mx-auto grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000">
        left
      </div>
    </Floating>
    <Floating
      placement="right"
      middleware={[
        {
          name: 'offset',
          options: {crossAxis: 20},
        },
      ]}
    >
      <div className="mx-auto grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000">
        right
      </div>
    </Floating>
  </div>
</Chrome>

### alignmentAxis

default: `null{:js}`

The same axis as `crossAxis{:.objectKey}` but applies only to
aligned placements and inverts the `end{:.string}` alignment.
When set to a number, it overrides the `crossAxis{:.objectKey}`
value.

A positive number will move the floating element in the direction
of the opposite edge to the one that is aligned, while a negative
number the reverse.

```js
offset({
  alignmentAxis: 20,
});
```

Here's how it differentiates from `crossAxis{:.objectKey}`:

<Chrome center className="pt-16 pb-24" tall>
  <div className="mt-4 flex flex-col gap-4 md:flex-row">
    <Floating
      placement="top-start"
      middleware={[
        {
          name: 'offset',
          options: {crossAxis: 20},
        },
      ]}
    >
      <div className="mx-auto grid h-32 w-48 place-items-center border-2 border-dashed border-gray-1000 text-center">
        top-start <br />{' '}
        <strong className="text-inherit">(crossAxis)</strong>
      </div>
    </Floating>
    <Floating
      placement="top-end"
      middleware={[
        {
          name: 'offset',
          options: {crossAxis: 20},
        },
      ]}
    >
      <div className="mx-auto grid h-32 w-48 place-items-center border-2 border-dashed border-gray-1000 text-center">
        top-end <br />{' '}
        <strong className="text-inherit">(crossAxis)</strong>
      </div>
    </Floating>
  </div>
  <div className="flex flex-col gap-4 md:flex-row">
    <Floating
      placement="top-start"
      middleware={[
        {
          name: 'offset',
          options: {alignmentAxis: 20},
        },
      ]}
    >
      <div className="mx-auto grid h-32 w-48 place-items-center border-2 border-dashed border-gray-1000 text-center">
        top-start <br />{' '}
        <strong className="text-inherit">(alignmentAxis)</strong>
      </div>
    </Floating>
    <Floating
      placement="top-end"
      middleware={[
        {
          name: 'offset',
          options: {alignmentAxis: 20},
        },
      ]}
    >
      <div className="mx-auto grid h-32 w-48 place-items-center border-2 border-dashed border-gray-1000 text-center">
        top-end <br />{' '}
        <strong className="text-inherit">(alignmentAxis)</strong>
      </div>
    </Floating>
  </div>
</Chrome>

## Creating custom placements

While you can only choose 12 different placements as part of the
core library, you can use the `offset(){:js}` middleware to
create **any** placement you want.

For example, although the library doesn't provide a placement for
centering on both axes, offset enables this via the function
option by allowing you to read the rects:

```js
computePosition(referenceEl, floatingEl, {
  middleware: [
    // Assumes placement is 'bottom' (the default)
    offset(({rects}) => {
      return (
        -rects.reference.height / 2 - rects.floating.height / 2
      );
    }),
  ],
});
```

<Chrome center className="pt-16 pb-24">
  <div className="flex gap-4">
    <Floating
      middleware={[
        {
          name: 'offset',
          options: ({rects}) =>
            -rects.reference.height / 2 -
            rects.floating.height / 2,
        },
      ]}
    >
      <div className="mx-auto grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000">
        10px
      </div>
    </Floating>
  </div>
</Chrome>

In this case, the function option starts from the default bottom
placement, then using that starting point, returns an offset to
center the floating element on both axes.

A diagonal placement is also possible:

```js
computePosition(referenceEl, floatingEl, {
  placement: 'top-start',
  middleware: [
    offset(({rects}) => ({
      alignmentAxis: -rects.floating.width,
    })),
  ],
});
```

<Chrome center className="pt-16 pb-24">
  <div className="flex gap-4">
    <Floating
      placement="top-start"
      middleware={[
        {
          name: 'offset',
          options: ({rects}) => ({
            alignmentAxis: -rects.floating.width,
          }),
        },
      ]}
    >
      <div className="mx-auto grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000" />
    </Floating>
  </div>
</Chrome>

This time, `'top-start'{:js}` was used as the starting point.

So, it's straightforward to allow this:

```js
computePosition(referenceEl, floatingEl, {
  placement: 'center',
});
```

With a wrapper, like this:

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

const centerOffset = offset(({rects}) => {
  return -rects.reference.height / 2 - rects.floating.height / 2;
});

export function computePosition(
  referenceEl,
  floatingEl,
  options
) {
  const isCentered = options.placement === 'center';
  const placement = isCentered ? 'bottom' : options.placement;
  const middleware = [
    isCentered && centerOffset,
    ...(options.middleware || []),
  ];

  return base(referenceEl, floatingEl, {
    ...options,
    placement,
    middleware,
  });
}
```

<Notice>
  What about centering on the screen? You don't need Floating UI
  to do that 😀 — pure CSS works fine. You only need Floating UI
  if you want to center over a particular element, not the whole
  screen.
</Notice>
