FezVrasta/popper.js

View on GitHub
website/pages/docs/useFloating.mdx

Summary

Maintainability
Test Coverage
<PageCard>

# useFloating

The main Hook of the library that acts as a controller for all
other Hooks and components.

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

```js
import {useFloating} from '@floating-ui/react';
```

</ShowFor>

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

```js
import {useFloating} from '@floating-ui/react-dom';
```

</ShowFor>

</PageCard>

## Usage

Call the Hook inside a component.

```js
function App() {
  const {refs, floatingStyles} = useFloating();
  return (
    <>
      <div ref={refs.setReference} />
      <div ref={refs.setFloating} style={floatingStyles} />
    </>
  );
}
```

## Options

The Hook accepts an object of options to configure its behavior.

```js
useFloating({
  // options
});
```

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

```ts
interface UseFloatingOptions {
  placement?: Placement;
  strategy?: 'fixed' | 'absolute';
  transform?: boolean;
  middleware?: Array<Middleware | undefined | null | false>;
  open?: boolean;
  onOpenChange?(
    open: boolean,
    event?: Event,
    reason?: OpenChangeReason,
  ): void;
  elements?: {
    reference?: ReferenceElement | null;
    floating?: FloatingElement | null;
  };
  whileElementsMounted?(
    reference: ReferenceElement,
    floating: FloatingElement,
    update: () => void,
  ): () => void;
  nodeId?: string;
}
```

</ShowFor>

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

```ts
interface UseFloatingOptions {
  placement?: Placement;
  strategy?: 'fixed' | 'absolute';
  transform?: boolean;
  middleware?: Array<Middleware | undefined | null | false>;
  open?: boolean;
  elements?: {
    reference?: ReferenceElement | null;
    floating?: FloatingElement | null;
  };
  whileElementsMounted?(
    reference: ReferenceElement,
    floating: FloatingElement,
    update: () => void,
  ): () => void;
}
```

</ShowFor>

### `placement{:.key}`

default: `'bottom'{:js}`

The placement of the floating element relative to the reference
element.

```js
useFloating({
  placement: 'left',
});
```

12 strings are available:

```ts
type Placement =
  | 'top'
  | 'top-start'
  | 'top-end'
  | 'right'
  | 'right-start'
  | 'right-end'
  | 'bottom'
  | 'bottom-start'
  | 'bottom-end'
  | 'left'
  | 'left-start'
  | 'left-end';
```

The `-start{:.string}` and `-end{:.string}` alignments are
[logical](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties)
and will adapt to the writing direction (e.g. RTL) as expected.

<Notice>
  You aren't limited to just these 12 placements though.
  [`offset`](/docs/offset#creating-custom-placements) allows you
  to create _any_ placement.
</Notice>

### `strategy{:.key}`

default: `'absolute'{:js}`

This is the type of CSS position property to use. Two strings are
available:

```ts
type Strategy = 'absolute' | 'fixed';
```

```js
useFloating({
  strategy: 'fixed',
});
```

These strategies are differentiated as follows:

- `'absolute'{:js}` — the floating element is positioned relative
  to its nearest positioned ancestor. With most layouts, this
  usually requires the browser to do the least work when updating
  the position.
- `'fixed'{:js}` — the floating element is positioned relative to
  its nearest containing block (usually the viewport). This is
  useful when the reference element is also fixed to reduce
  jumpiness with positioning while scrolling. It will in many
  cases also
  ["break" the floating element out of a clipping ancestor](/docs/misc#clipping).

### `transform{:.key}`

default: `true{:js}`

Whether to use CSS transforms to position the floating element
instead of layout (`top` and `left` CSS properties).

```js
useFloating({
  transform: false,
});
```

CSS transforms are more performant, but can cause conflicts with
transform animations. In that case, you can make the positioned
floating element a wrapper to avoid the conflict:

```js
<div ref={refs.setFloating} style={floatingStyles}>
  <div style={transitionStyles}>Content</div>
</div>
```

<Notice>
  When using layout instead of transforms, ensure that the
  floating element has a fixed width or sets a `width: max-content{:sass}` to
  prevent it from resizing.
</Notice>

### `middleware{:.key}`

default: `[]{:js}`

An array of middleware objects that change the positioning of the
floating element.

```js
useFloating({
  middleware: [
    // ...
  ],
});
```

When you want granular control over how the floating element is
positioned, middleware are used. They read the current
coordinates, optionally alter them, and/or provide data for
rendering. They compose and work together to produce the final
coordinates which are in the `floatingStyles` object.

The following are included in the package:

#### Placement modifiers

These middleware alter the base placement coordinates.

- [`offset`](/docs/offset) modifies the placement to add distance
  or margin between the reference and floating elements.

- [`inline`](/docs/inline) positions the floating element
  relative to individual client rects rather than the bounding
  box for better precision.

#### Visibility optimizers

These middleware alter the coordinates to ensure the floating
element stays on screen optimally.

- [`shift`](/docs/shift) prevents the floating element from
  overflowing a clipping container by shifting it to stay in
  view.

- [`flip`](/docs/flip) prevents the floating element from
  overflowing a clipping container by flipping it to the opposite
  placement to stay in view.

- [`autoPlacement`](/docs/autoPlacement) automatically chooses a
  placement for you using a "most space" strategy.

- [`size`](/docs/size) resizes the floating element, for example
  so it will not overflow a clipping container, or to match the
  width of the reference element.

#### Data providers

These middleware only provide data and do not alter the
coordinates.

- [`arrow`](/docs/arrow) provides data to position an inner
  element of the floating element such that it is centered to its
  reference element.

- [`hide`](/docs/hide) provides data to hide the floating element
  in applicable situations when it no longer appears attached to
  its reference element due to different clipping contexts.

#### Option reactivity

When using React state and middleware, stateful values inside
_function options_ (useful when deriving from middleware state)
aren't fresh or reactive.

```js
const [value, setValue] = useState(0);
// Reactive and fresh:
offset(value);
// Not reactive or fresh:
offset(() => value);
```

Calling a middleware function returns an object with an
`options{:.key}` key. These keys can hold the dependencies of the
options object, allowing deep comparison to enable reactivity.

Here's an example:

```js
import {offset} from '@floating-ui/react';

function App() {
  const [value, setValue] = useState(0);

  useFloating({
    middleware: [
      // Updates when `value` changes ✅
      offset(value),

      // Does not update when `value` changes ❌
      offset(() => value),

      // Updates when `value` changes ✅
      {
        ...offset(() => value),
        options: [value],
      },
    ],
  });
}
```

As a wrapper:

```js
const reactiveOffset = (options, deps) => ({
  ...offset(options),
  options: deps,
});

reactiveOffset(() => value, [value]);
```

### `elements{:.key}`

default: `undefined{:js}`

An object of elements passed to the Hook, which is useful for
externally passing them, as an alternative to the `refs{:.const}`
object setters.

The elements must be held in state (not plain refs) to ensure
that they are reactive.

```js
const [reference, setReference] = useState(null);

const {refs} = useFloating({
  elements: {
    reference,
  },
});

return (
  <>
    <div ref={setReference} />
    <div ref={refs.setFloating} />
  </>
);
```

You can also do the inverse of the above, or pass both
externally.

### `whileElementsMounted{:.function}`

default: `undefined{:js}`

A function that is called when the reference and floating
elements are mounted, and returns a cleanup function called when
they are unmounted.

```js
useFloating({
  whileElementsMounted: (reference, floating, update) => {
    // ...
    return () => {
      // ...
    };
  },
});
```

This allows you to pass [`autoUpdate`](/docs/autoUpdate) whose
signature matches the option, to ensure the floating element
remains anchored to the reference element:

```js
import {autoUpdate} from '@floating-ui/react';

useFloating({
  whileElementsMounted: autoUpdate,
});
```

<Notice type="warning">
  Only use this option if your floating element is _conditionally
  rendered_, not hidden with CSS. Use an Effect to call and clean
  up `autoUpdate` in the latter scenario.
</Notice>

### `open{:.key}`

default: `false{:js}`

Whether the floating element is open or not, which allows you to
determine if the floating element has been positioned yet.

```js {4}
const [isOpen, setIsOpen] = useState(false);

const {isPositioned} = useFloating({
  open: isOpen,
});

// Once `isOpen` flips to `true`, `isPositioned` will switch to `true`
// asynchronously. We can use an Effect to determine when it has
// been positioned.
useEffect(() => {
  if (isPositioned) {
    // ...
  }
}, [isPositioned]);
```

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

### `onOpenChange{:.function}`

default: `undefined{:js}`

A function that is called when the `open{:.key}` state should
change. By default, passing the setter of the `open{:.key}` state
will be sufficient:

```js
const [isOpen, setIsOpen] = useState(false);

useFloating({
  open: isOpen,
  onOpenChange: setIsOpen,
});
```

{/* prettier-ignore */}
Since it's an event callback function, it allows you to
conditionally react to the state changing, plus determine the <WordHighlight id="a" children="event" />
and <WordHighlight id="b" children="reason" /> that caused the
change.

```js /event/#a /reason/#b
useFloating({
  open: isOpen,
  onOpenChange(isOpen, event, reason) {
    setIsOpen(isOpen);
    event && console.log(event); // e.g. MouseEvent
    reason && console.log(reason); // e.g. 'hover'
  },
});
```

Most open change events have a reason and event attached, but not
all.

```ts
type OpenChangeReason =
  | 'outside-press'
  | 'escape-key'
  | 'ancestor-scroll'
  | 'reference-press'
  | 'click'
  | 'hover'
  | 'focus'
  | 'list-navigation'
  | 'safe-polygon';
```

### `nodeId{:.key}`

default: `undefined{:js}`

A unique node ID for the floating element when using a
[`FloatingTree`](/docs/FloatingTree).

</ShowFor>

## Return value

The Hook returns the following type:

```ts
interface UseFloatingReturn {
  context: FloatingContext;
  placement: Placement;
  strategy: Strategy;
  x: number;
  y: number;
  middlewareData: MiddlewareData;
  isPositioned: boolean;
  update(): void;
  floatingStyles: React.CSSProperties;
  refs: {
    reference: React.MutableRefObject<ReferenceElement | null>;
    floating: React.MutableRefObject<HTMLElement | null>;
    domReference: React.MutableRefObject<Element | null>;
    setReference(node: RT | null): void;
    setFloating(node: HTMLElement | null): void;
    setPositionReference(node: ReferenceElement): void;
  };
  elements: {
    reference: RT | null;
    floating: HTMLElement | null;
  };
}
```

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

### `context{:.const}`

This object contains the context data provided to relevant Hooks
and components.

```js
const {context} = useFloating();
```

</ShowFor>

### `placement{:.const}`

The **final** placement of the floating element relative to the
reference element. Unlike the one passed in the options, this one
can be mutated by middleware like `flip(){:js}`. This is
necessary to determine the actual side of the floating element
for styling.

```js
const {placement} = useFloating();
```

### `strategy{:.const}`

The positoning strategy of the floating element.

```js
const {strategy} = useFloating();
```

### `x{:.const}`

The final x-coordinate of the floating element. This can be used
as an alternative to `floatingStyles` to manually position the
floating element with custom CSS.

```js
const {x} = useFloating();
```

### `y{:.const}`

The final y-coordinate of the floating element. This can be used
as an alternative to `floatingStyles` to manually position the
floating element with custom CSS.

```js
const {y} = useFloating();
```

### `middlewareData{:.const}`

The data provided by any middleware used.

```js
const {middlewareData} = useFloating();
```

### `isPositioned{:.const}`

Whether the floating element has been positioned yet when used
inside an Effect (not during render). Requires the `open{:.key}`
option to be passed.

```js
const {isPositioned} = useFloating();
```

### `update{:.const}`

A function that updates the floating element's position manually.

```js
const {update} = useFloating();
```

### `floatingStyles{:.const}`

The styles that should be applied to the floating element.

```js
const {floatingStyles} = useFloating();
```

### `refs{:.const}`

The refs that should be applied to the reference and floating
elements.

```js
const {refs} = useFloating();
```

#### `reference`

A ref for the reference element. You can access this inside an
event handler or in an Effect.

```js
const {refs} = useFloating();
useEffect(() => {
  console.log(refs.reference.current);
}, [refs]);
```

#### `floating`

A ref for the floating element. You can access this inside an
event handler.

For usage in Effects, prefer using `elements.floating{:js}`,
since it's not guaranteed the floating element will be available
on the first pass.

```js
const {refs} = useFloating();
// Inside an event handler:
console.log(refs.floating.current);
```

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

#### `domReference`

A ref for the DOM reference element (if available). You can
access this inside an event handler or in an Effect.

```js
const {refs} = useFloating();
useEffect(() => {
  console.log(refs.domReference.current);
}, [refs]);
```

This differs from `reference` in that it is guaranteed to be a
DOM reference, while the former can be a
[virtual element](/docs/virtual-elements).

</ShowFor>

#### `setReference`

A function that sets the reference element.

```js
const {refs} = useFloating();
return <div ref={refs.setReference} />;
```

#### `setFloating`

A function that sets the floating element.

```js
const {refs} = useFloating();
return <div ref={refs.setFloating} />;
```

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

#### `setPositionReference`

A function that sets the positioning reference element, to
separate it from the events reference. This can be either a real
or [virtual](/docs/virtual-elements) element.

```js
const {refs} = useFloating();
return <div ref={refs.setPositionReference} />;
```

</ShowFor>

### `elements{:.const}`

The elements as set by the refs, useful for access during
rendering or when needing to reactively check if the element
exists.

```js
const {elements} = useFloating();
```

#### `reference`

The reference element. May be virtual.

```js
const {elements} = useFloating();
console.log(elements.reference);
```

#### `floating`

The floating element. Enables you to reactively check if the
floating element exists inside Effects, notable when using
`<FloatingPortal>{:js}`, as it won't be available on the first
pass.

```js
const {elements} = useFloating();
React.useEffect(() => {
  if (!elements.floating) return;
  // ...
}, [elements.floating]);
```

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

#### `domReference`

The DOM reference element.

```js
const {elements} = useFloating();
console.log(elements.domReference);
```

</ShowFor>