# arrow

Provides data to position an inner element of the floating
element (usually a triangle or caret) so that it appears centered
to the reference element.

<div className="flex flex-col gap-4">
  <Chrome center className="h-96">
    <Floating arrow>
      <div className="grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000" />
    </Floating>
  </Chrome>
</div>

This is useful to add an additional visual cue to the floating
element about which element it is referring to.

<Notice>
  If you're using React, the
  [`FloatingArrow`](/docs/FloatingArrow) component renders out a
  customizable arrow element and applies the positioning styles
  for you.
</Notice>

## Usage

The layout box of the arrow element should be a square with equal
width and height. Inner or pseudo-elements may have a different
aspect ratio.

Given an arrow element inside your floating element:

```html
<div id="tooltip">
  Tooltip text
  <div id="arrow"></div>
</div>
```

```css
#arrow {
  position: absolute;
}
```

Pass it to the `arrow(){:js}` middleware and assign the dynamic
styles:

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

const arrowEl = document.querySelector('#arrow');

computePosition(referenceEl, floatingEl, {
  middleware: [
    arrow({
      element: arrowEl,
    }),
  ],
}).then(({middlewareData}) => {
  if (middlewareData.arrow) {
    const {x, y} = middlewareData.arrow;

    Object.assign(arrowEl.style, {
      left: x != null ? `${x}px` : '',
      top: y != null ? `${y}px` : '',
    });
  }
});
```

<Notice type="error" title="Important">
  Depending on the placement, either `x` or `y` will be
  `undefined{:js}`. The above code checks for `null{:js}` and
  `undefined{:js}` simultaneously. Don't remove `!= null{:js}`,
  because either value can be falsy (0), causing a bug!
</Notice>

This middleware is designed only to position the arrow on one
axis (`x` for `'top'{:js}` or `'bottom'{:js}` placements). The
other axis is considered "static", which means it does not need
to be positioned dynamically.

You may however want to position **both** axes statically in the
following scenario:

- The reference element is either wider or taller than the
  floating element;
- The floating element is using an edge alignment
  (`-start{:.string}` or `-end{:.string}` placement).

## Visualization

To help you understand how this middleware works, here is a
[visualization tutorial on CodeSandbox](https://codesandbox.io/s/mystifying-kare-ee3hmh?file=/src/index.js).

## Order

`arrow(){:js}` should generally be placed toward the end of your
middleware array, after `shift(){:js}` (if used).

## Placement

To know which side the floating element is actually placed at for
the static axis offset of the arrow, the placement is returned:

```js
computePosition(referenceEl, floatingEl, {
  placement: 'top',
  middleware: [flip(), arrow({element: arrowEl})],
}).then((data) => {
  // The final placement can be 'bottom' or 'top'
  const placement = data.placement;
});
```

### React

```js
// The final placement can be 'bottom' or 'top'
const {placement} = useFloating({
  placement: 'top',
  middleware: [flip(), arrow({element: arrowEl})],
});
```

## Options

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

```ts
interface Options {
  element: Element;
  padding?: Padding;
}
```

### element

default: `undefined{:js}`

This is the arrow element to be positioned.

```js
arrow({
  element: document.querySelector('#arrow'),
});
```

### padding

default: `0{:js}`

This describes the padding between the arrow and the edges of the
floating element. If your floating element has
`border-radius{:.function}`, this will prevent it from
overflowing the corners.

```js
arrow({
  element: document.querySelector('#arrow'),
  padding: 5, // stop 5px from the edges of the floating element
});
```

### Deriving options from state

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

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

## Data

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

```ts
interface Data {
  x?: number;
  y?: number;
  centerOffset: number;
}
```

### x

This property exists if the arrow should be offset on the x-axis.

### y

This property exists if the arrow should be offset on the y-axis.

### centerOffset

This property describes where the arrow actually is relative to
where it could be if it were allowed to overflow the floating
element in order to stay centered to the reference element.

This enables two useful things:

- You can hide the arrow if it can't stay centered to the
  reference, i.e. `centerOffset !== 0{:js}`.
- You can interpolate the shape of the arrow (e.g. skew it) so it
  stays centered as best as possible.
