# size

A visibility optimizer and data provider that allows you to
change the size of the floating element.

<div className="flex flex-col gap-4">
  <Chrome
    label="Scroll the container"
    center
    scrollable="y"
    className="h-96"
  >
    <Floating
      tooltipStyle={{
        height: 300,
        overflow: 'hidden',
        maxHeight: 0,
      }}
      middleware={[{name: 'size', options: {padding: 5}}]}
    >
      <div className="grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000" />
    </Floating>
  </Chrome>
</div>

This is useful for long dropdowns that become scrollable without
specifying a fixed height, or matching the floating element's
width with its reference element.

## Usage

If your floating element's content cannot be resized such as in
the example, you can make the floating element scrollable with
`overflow: scroll{:sass}` (or `auto{:.param}`). Ensure your CSS
is using `box-sizing: border-box{:sass}`!

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

computePosition(referenceEl, floatingEl, {
  middleware: [
    size({
      apply({availableWidth, availableHeight, elements}) {
        // Do things with the data, e.g.
        Object.assign(elements.floating.style, {
          maxWidth: `${availableWidth}px`,
          maxHeight: `${availableHeight}px`,
        });
      },
    }),
  ],
});
```

## Options

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

```ts
interface Options extends DetectOverflowOptions {
  apply?: (
    state: MiddlewareState & {
      availableWidth: number;
      availableHeight: number;
    }
  ) => void;
}
```

### apply

default: `undefined{:js}`

Unlike other middleware, in which you assign styles after
`computePosition(){:js}` has done its work, `size(){:js}` has its
own `apply{:.function}` function to do the work during the
lifecycle:

```js
size({
  apply({availableWidth, availableHeight, ...state}) {
    // Style mutations here
  },
});
```

#### availableWidth

Represents how wide the floating element can be before it will
overflow its clipping context. You'll generally set this as the
`maxWidth{:.objectKey}` CSS property.

#### availableHeight

Represents how tall the floating element can be before it will
overflow its clipping context. You'll generally set this as the
`maxHeight{:.objectKey}` CSS property.

#### ...middlewareState

See [MiddlewareState](/docs/middleware#middlewarestate).

Many useful properties are also accessible via this callback,
such as `rects{:.objectKey}` and `elements{:.objectKey}`, the
latter of which is useful in the context of React where you need
access to the floating element and it does not exist in scope.

### ...detectOverflowOptions

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

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

### Deriving options from state

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

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

## Using with flip

Using `size(){:js}` together with `flip(){:js}` enables some
useful behavior. The floating element can be resized, thus
allowing it to prefer its initial placement as much as possible,
until it reaches a minimum size, at which point it will flip.

If you're using the `padding{:.objectKey}` option in either
middleware, ensure they share the **same value**.

### bestFit

The `'bestFit'{:js}` fallback strategy in the `flip(){:js}`
middleware is the default, which ensures the best fitting
placement is used. In this scenario, place `size(){:js}`
**after** `flip(){:js}`:

```js
const middleware = [
  flip(),
  size({
    apply({availableWidth, availableHeight}) {
      // ...
    },
  }),
];
```

<div className="flex flex-col gap-4">
  <Chrome
    label="Scroll the container"
    center
    scrollable="y"
    className="h-96"
  >
    <Floating
      tooltipStyle={{
        height: 200,
        overflow: 'hidden',
        maxHeight: 0,
      }}
      middleware={[
        {name: 'flip', options: {padding: 5}},
        {name: 'size', options: {padding: 5}},
      ]}
    >
      <div className="grid h-32 w-32 place-items-center border-2 border-dashed border-gray-1000" />
    </Floating>
  </Chrome>
</div>

This strategy ensures the floating element stays in view at all
times at the most optimal size.

### initialPlacement

If instead, you want the initial placement to take precedence,
and are setting a minimum acceptable size, place `size(){:js}`
**before** `flip(){:js}`:

```js
const middleware = [
  size({
    apply({availableHeight, elements}) {
      Object.assign(elements.floating.style, {
        // Minimum acceptable height is 50px.
        // `flip` will then take over.
        maxHeight: `${Math.max(50, availableHeight)}px`,
      });
    },
  }),
  flip({
    fallbackStrategy: 'initialPlacement',
  }),
];
```

## Match reference width

A common feature of select dropdowns is that the dropdown matches
the width of the reference regardless of its contents. You can
also use `size(){:js}` for this, as the `Rect{:.class}`s get
passed in:

```js /rects/
size({
  apply({rects}) {
    Object.assign(floatingEl.style, {
      width: `${rects.reference.width}px`,
    });
  },
});
```
