<PageCard>

# Middleware

Objects that change the positioning of the floating element,
executed in order as a queue.

</PageCard>

Middleware allow you to customize the behavior of the positioning
and be as granular as you want, adding your own custom logic.

`computePosition(){:js}` starts with initial positioning via
`placement{:.key}` — then middleware are executed as an
in-between "middle" step of the initial placement computation and
eventual return of data for rendering.

Each middleware is executed in order:

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

```js
computePosition(referenceEl, floatingEl, {
  placement: 'right',
  middleware: [],
});
```

</ShowFor>

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

```js
useFloating({
  placement: 'right',
  middleware: [],
});
```

</ShowFor>

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

```js
useFloating(reference, floating, {
  placement: 'right',
  middleware: [],
});
```

</ShowFor>

## Example

```js
const shiftByOnePixel = {
  name: 'shiftByOnePixel',
  fn({x, y}) {
    return {
      x: x + 1,
      y: y + 1,
    };
  },
};
```

This (not particularly useful) middleware adds `1{:js}` pixel to
the coordinates. To use this middleware, add it to your
`middleware{:.key}` array:

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

```js
computePosition(referenceEl, floatingEl, {
  placement: 'right',
  middleware: [shiftByOnePixel],
});
```

</ShowFor>

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

```js
useFloating({
  placement: 'right',
  middleware: [shiftByOnePixel],
});
```

</ShowFor>

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

```js
useFloating(reference, floating, {
  placement: 'right',
  middleware: [shiftByOnePixel],
});
```

</ShowFor>

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

Here, `computePosition(){:js}` will compute coordinates that will
place the floating element to the `right{:.string}` center of the
reference element, lying flush with it.

</ShowFor>

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

Here, `useFloating(){:js}` will compute coordinates that will
place the floating element to the `right{:.string}` center of the
reference element, lying flush with it.

</ShowFor>

Middleware are then executed, resulting in these coordinates
getting shifted by one pixel. Then that data is returned for
rendering.

### Shape

A middleware is an object that has a `name{:.key}` property and a
`fn{:.function}` property. The `fn{:.function}` property provides
the logic of the middleware, which returns new positioning
coordinates or useful data.

### Data

Any data can be passed via an optional `data{:.key}` property of
the object that is returned from `fn{:.function}`. This will be
accessible to the consumer via the `middlewareData` property:

```js {7-9}
const shiftByOnePixel = {
  name: 'shiftByOnePixel',
  fn({x, y}) {
    return {
      x: x + 1,
      y: y + 1,
      data: {
        amount: 1,
      },
    };
  },
};
```

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

```js
computePosition(referenceEl, floatingEl, {
  middleware: [shiftByOnePixel],
}).then(({middlewareData}) => {
  console.log(middlewareData.shiftByOnePixel);
});
```

</ShowFor>

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

```js
const {middlewareData} = useFloating({
  middleware: [shiftByOnePixel],
});
console.log(middlewareData.shiftByOnePixel);
```

</ShowFor>

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

```js
const {middlewareData} = useFloating(reference, floating, {
  middleware: [shiftByOnePixel],
});

// Available once mounted and positioned as:
// `middlewareData.value.shiftByOnePixel`
```

</ShowFor>

### Function

You may notice that Floating UI's packaged middleware are
actually functions. This is so you can pass options in, changing
how the middleware behaves:

```js
const shiftByAmount = (amount = 0) => ({
  name: 'shiftByAmount',
  options: amount,
  fn: ({x, y}) => ({
    x: x + amount,
    y: y + amount,
  }),
});
```

It returns an object and uses a closure to pass the configured
behavior:

```js
const middleware = [shiftByAmount(10)];
```

The `options{:.key}` key on a middleware object holds the
dependencies, allowing deep comparison reactivity.

### Always return an object

Inside `fn{:.function}` make sure to return an object. It doesn't
need to contain properties, but to remind you that it should be
pure, you must return an object. Never mutate any values that get
passed in from `fn{:.function}`.

## MiddlewareState

An object is passed to `fn{:.function}` containing useful data
about the middleware lifecycle being executed.

In the previous examples, we destructured `x{:.param}` and
`y{:.param}` out of the `fn{:.function}` parameter object. These
are only two properties that get passed into middleware, but
there are many more.

The properties passed are below:

```ts
interface MiddlewareState {
  x: number;
  y: number;
  initialPlacement: Placement;
  placement: Placement;
  strategy: Strategy;
  middlewareData: MiddlewareData;
  elements: Elements;
  rects: ElementRects;
  platform: Platform;
}
```

### `x{:.key}`

This is the x-axis coordinate to position the floating element
to.

### `y{:.key}`

This is the y-axis coordinate to position the floating element
to.

### `elements{:.key}`

This is an object containing the reference and floating elements.

### `rects{:.key}`

This is an object containing the `Rect{:.class}`s of the
reference and floating elements, an object of shape
`{width, height, x, y}`.

### `middlewareData{:.key}`

This is an object containing all the data of any middleware at
the current step in the lifecycle. The lifecycle loops over the
`middleware{:.key}` array, so later middleware have access to
data from any middleware run prior.

### `strategy{:.key}`

The positioning strategy.

### `initialPlacement{:.key}`

The initial (or preferred) placement passed in to
`computePosition(){:js}`.

### `placement{:.key}`

The stateful resultant placement. Middleware like
`flip{:.function}` change `initialPlacement{:.key}` to a new one.

### `platform{:.key}`

An object containing methods to make Floating UI work on the
current platform, e.g. DOM or React Native.

## Ordering

The order in which middleware are placed in the array matters, as
middleware **use** the coordinates that were returned from
previous ones. This means they perform their work based on the
current positioning state.

Three `shiftByOnePixel{:.const}` in the middleware array means
the coordinates get shifted by 3 pixels in total:

```js
const shiftByOnePixel = {
  name: 'shiftByOnePixel',
  fn: ({x, y}) => ({x: x + 1, y: y + 1}),
};
const middleware = [
  shiftByOnePixel,
  shiftByOnePixel,
  shiftByOnePixel,
];
```

If the later `shiftByOnePixel` implementations had a condition
based on the current value of `x{:.param}` and `y{:.param}`, the
condition can change based on their placement in the array.

Understanding this can help in knowing which order to place
middleware in, as placing a middleware before or after another
can produce a different result.

In general, `offset(){:js}` should always go at the beginning of
the middleware array, while `arrow(){:js}` and `hide(){:js}` at
the end. The other core middleware can be shifted around
depending on the desired behavior.

```js
const middleware = [
  offset(),
  // ...
  arrow({element: arrowElement}),
  hide(),
];
```

## Resetting the lifecycle

There are use cases for needing to reset the middleware lifecycle
so that other middleware perform fresh logic.

- When `flip(){:js}` and `autoPlacement(){:js}` change the
  placement, they reset the lifecycle so that other middleware
  that modify the coordinates based on the current
  `placement{:.key}` do not perform stale logic.
- `size(){:js}` resets the lifecycle with the newly applied
  dimensions, as many middleware read the dimensions to perform
  their logic.
- `inline(){:js}` resets the lifecycle when it changes the
  reference rect to a custom implementation, similar to a
  [Virtual Element](/docs/virtual-elements).

In order to do this, add a `reset{:.key}` property to the
returned object from `fn{:.function}`.

```ts
type Reset =
  | true
  | {
      placement?: Placement;
      // `true` will compute the new `rects` if the
      // dimensions were mutated. Otherwise, you can
      // return your own new rects.
      rects?: true | ElementRects;
    };
```

```js
const middleware = {
  name: 'middleware',
  fn() {
    if (someCondition) {
      return {
        reset: {
          placement: nextPlacement,
        },
      };
    }

    return {};
  },
};
```

Data supplied to `middlewareData{:.param}` is preserved by doing
this, so you can read it at any point after you've reset the
lifecycle.
