import inline from '../../assets/react.inline.jpg';

# React

This package provides React bindings for `@floating-ui/dom`, a
library that provides anchor positioning, and also interaction
primitives to build floating UI components.

<CircleImage name="react" inline={inline} />

With this package, you can create components such as tooltips,
popovers, dropdown menus, hover cards, modal dialogs, select
menus, comboboxes, and more.

## Goals

- **Provide building blocks**: pre-built floating components
  aren't exported, rather the primitives necessary to create
  different types of them.
- **Flexible and low-level**: at the cost of more code to setup,
  you get high control and flexibility.
- **Accessibility is prioritized**: first-class support is
  provided for creating accessible floating elements that work
  with assistive technology (keyboard usage and screen readers).

## Install

```bash
npm install @floating-ui/react
```

<Notice>

If you only need positioning, the following package is smaller in
size (the above one uses it as a dependency). This is useful if
you are controlling interactions yourself (e.g. a library).

```bash
npm install @floating-ui/react-dom
```

</Notice>

## Usage

There are two main parts to creating floating elements:

- [Positioning](/docs/react#positioning) — available for both
  packages
- [Interactions](/docs/react#interactions) — available for
  `@floating-ui/react{:.string}`

## Positioning

`useFloating(){:js}` is the main hook of each package.

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

function App() {
  const {refs, floatingStyles} = useFloating();

  return (
    <>
      <button ref={refs.setReference}>Button</button>
      <div ref={refs.setFloating} style={floatingStyles}>
        Tooltip
      </div>
    </>
  );
}
```

This will position the floating `Tooltip` element at the **bottom
center** of the `Button` element by default.

- `refs.setReference{:js}` is the reference (or anchor) element
  that is being referred to for positioning.
- `refs.setFloating{:js}` is the floating element that is being
  positioned relative to the reference element.
- `floatingStyles{:js}` is an object of positioning styles to
  apply to the floating element's `style{:.keyword}` prop.

The refs are functions to make them **reactive** — this ensures
changes to the reference or floating elements, such as with
conditional rendering, are handled correctly by updating the
position.

### External elements

Depending on your component tree, you may instead want to
synchronize with an external element instead of using refs.

```js /anchor/1,3-5#a /setAnchor/#b {13-15}
function App() {
  const [anchor, setAnchor] = useState(null);
  return (
    <>
      <button ref={setAnchor}>Button</button>
      <Tooltip anchor={anchor} />
    </>
  );
}

function Tooltip({anchor}) {
  const {refs, floatingStyles} = useFloating({
    elements: {
      reference: anchor,
    },
  });

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

Either element can be synchronized externally or via
`refs.set{Element}{:js}`.

<Notice title="Element reactivity" type="error">
  Make sure the elements are stored in <WordHighlight id="b">state</WordHighlight>. This makes them reactive to 
  changes, and avoids reading refs in render (forbidden by React).

```ts /useState/#b
const [anchor, setAnchor] = useState<Element | null>(null);

useFloating({
  elements: {
    reference: anchorRef.current, // ❌
    reference: anchor, // ✅
  },
});
```

</Notice>

## Positioning styles customization

By default, the floating element is positioned using
`transform{:.objectKey}` in the `floatingStyles` object. This is
the most performant way to position elements, but can be
disabled:

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

If you'd like to retain transform styles while allowing transform
animations, create a wrapper, where the outermost node is the
positioned one, and the inner is the actual styled element.

<Notice>
  When disabling transforms, add `width: max-content{:sass}` (or a fixed width) 
  to the floating element to prevent positioning issues due to layout affecting
  the floating element.
</Notice>

The hook also returns the coordinates and positioning strategy
directly if `floatingStyles` is not suitable:

```js
const {x, y, strategy} = useFloating();
return (
  <div
    style={{
      position: strategy,
      left: x,
      top: y,
      width: 'max-content',
    }}
  />
);
```

## Anchoring

To ensure the floating element remains **anchored** to its
reference element in a variety of scenarios without detaching,
you can pass the [`autoUpdate`](/docs/autoUpdate) utility to the
`whileElementsMounted{:.objectKey}` prop:

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

// Inside your component
useFloating({
  whileElementsMounted: autoUpdate,
});
```

This prop is called whenever both the reference and floating
elements are mounted, and cleans up if they change. This allows
listeners that automatically update the position to be
registered.

<Notice title="Warning" type="warning">
Ensure you are using conditional rendering for the floating
element, not an opacity/visibility/display style. If you are
using CSS to hide it, instead of conditional rendering, use an
effect to register and clean up `autoUpdate` instead of the
`whileElementsMounted{:.objectKey}` prop.
</Notice>

To pass options to `autoUpdate`:

```js
useFloating({
  whileElementsMounted(...args) {
    const cleanup = autoUpdate(...args, {animationFrame: true});
    // Important! Always return the cleanup function.
    return cleanup;
  },
});
```

### Manual updating

The hook returns an `update(){:js}` function to update the
position at will, manually:

```js
const {update} = useFloating();
<Panel onResize={update} />;
```

## Return value

The hook
[returns all the values from `computePosition`](/docs/computePosition#return-value),
plus some extras to work with React. This includes data about the
final placement and middleware data which are useful when
rendering.

## Options

The hook accepts all the
[options from `computePosition`](/docs/computePosition#options),
which allows you to customize the position. Here's an example:

```js
import {
  useFloating,
  offset,
  flip,
  shift,
} from '@floating-ui/react';

// Inside your component
useFloating({
  placement: 'right',
  middleware: [offset(10), flip(), shift()],
});
```

[Middleware](/docs/computePosition#middleware) can alter the
positioning from the basic `placement{:.objectKey}`, act as
visibility optimizers, or provide data to use.

The docs for the middleware that were passed are available here:

- [`offset`](/docs/offset)
- [`flip`](/docs/flip)
- [`shift`](/docs/shift)

All of these are re-exported from the base `@floating-ui/dom`
library.

## Refs

To access the DOM elements, you can either access the refs:

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

// Inside an effect or event handler:
refs.reference.current;
refs.floating.current;
```

Or the elements directly:

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

// During render, unlike the refs:
elements.reference;
elements.floating;
```

External elements can be synchronized using the
`elements{:.objectKey}` option like so, if they live outside the
component:

```js
function MyComponent({referenceEl, floatingEl}) {
  const {refs} = useFloating({
    elements: {
      reference: referenceEl,
      floating: floatingEl,
    },
  });
}
```

## Effects

Positioning is done in an async function, which means the
position is ready during a microtask, after layout effects are
executed. This means initially, the floating element is situated
at the top-left (0, 0) of its offset container — so calling DOM
methods that cause side-effects like scrolling will result in
unexpected behavior.

The hook returns an `isPositioned{:.const}` boolean that lets you
know if the floating element has been positioned:

```js
const [isOpen, setIsOpen] = useState(false);
const {isPositioned} = useFloating({
  // Synchronize `isPositioned` with an `open` state.
  open: isOpen,
});

// Each time the floating element opens, we want to focus and
// scroll some element into view.
useLayoutEffect(() => {
  if (isPositioned) {
    someElement.focus();
    someElement.scrollIntoView();
  }
}, [isPositioned]);
```

The `open{:.objectKey}` option accepts a boolean that represents
the open/close state of the floating element. This ensures you
can wait each time it opens when the host component does not
unmount, which is necessary in cases where the reference element
relocates on the page.

## Arrow

The `arrow` module exported from this package allows refs in
addition to elements:

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

// Inside your component
const arrowRef = useRef(null);
useFloating({
  middleware: [
    arrow({
      element: arrowRef,
    }),
  ],
});
```

If you need your arrow to be _reactive_ to updates (e.g. showing
or hiding the arrow with conditional rendering while the floating
element is open), you should use state instead. Alternatively,
you can use `visibility: hidden{:sass}` CSS to hide it and keep
using a plain ref.

For details on creating an arrow element, see the
[`arrow` middleware](/docs/arrow) page.

## Testing

When testing your components, ensure you flush microtasks
immediately after the floating element renders. This will avoid
the `act` warning.

```js
import {act} from '@testing-library/react';

test('something', async () => {
  render(<Tooltip open />);
  await act(async () => {}); // Flush microtasks.
  // Position state is ready by this line.
});
```

You may use this a lot, so you can create a custom function:

```js
const waitForPosition = () => act(async () => {});

test('something', async () => {
  render(<Tooltip open />);
  await waitForPosition();
  expect(screen.queryByRole('tooltip')).toBeInTheDocument();
});
```

## Narrow reference type

Because the `refs.setReference{:js}` callback ref accepts a
[virtual element](/docs/virtual-elements), you may need to narrow
the type when performing DOM operations on the ref:

```js
const {refs} = useFloating<HTMLButtonElement>();

// @floating-ui/react
// refs.domReference.current is now of type HTMLButtonElement

// @floating-ui/react-dom
// refs.reference.current is now of type HTMLButtonElement
```

In the full package, it is narrowed on `refs.domReference{:js}`,
as the
[position can be separated](/docs/react#changing-the-positioning-reference-while-retaining-events).

## 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);
```

To ensure they are reactive, specify the dependencies in the
`options{:.objectKey}` key:

```js {7}
const [value, setValue] = useState(0);

useFloating({
  middleware: [
    {
      ...offset(() => value),
      options: [value],
    },
  ],
});
```

---

This is where the compatibility with the leaner
`@floating-ui/react-dom` package ends. The following docs now
only apply to `@floating-ui/react`.

[View examples](/docs/react-examples), or read below to
understand the basics.

## Interactions

<div className="mx-auto flex flex-wrap items-center justify-center gap-2 md:justify-between">
  <img
    className="card relative top-[1rem] inline-block sm:left-[5rem] md:top-0 md:left-0"
    src="/all-inputs.png"
    alt="Designed for all inputs"
    width={335}
    height={225}
    loading="lazy"
  />
  <img
    className="card relative top-[-1rem] inline-block sm:left-[-5rem] md:left-0 md:top-0"
    src="/safe-cursor-polygon.png"
    alt="Safe cursor polygon"
    width={335}
    height={225}
    loading="lazy"
  />
</div>

To add interactions, such as the ability to only show a floating
element while hovering over its reference element, the hook must
first accept the following two options:

- `open{:.objectKey}` — a
  <WordHighlight id="a">boolean</WordHighlight> that represents whether
  the floating element is currently rendered.
- `onOpenChange{:.objectKey}` — an <WordHighlight id="b">event
  callback</WordHighlight> invoked when the open boolean state
  should change.

```js /isOpen/#a /setIsOpen/#b
import {useFloating} from '@floating-ui/react';

function App() {
  const [isOpen, setIsOpen] = useState(false);

  const {refs, floatingStyles} = useFloating({
    open: isOpen,
    onOpenChange: setIsOpen,
  });

  return (
    <>
      <button ref={refs.setReference}>Button</button>
      {isOpen && (
        <div ref={refs.setFloating} style={floatingStyles}>
          Tooltip
        </div>
      )}
    </>
  );
}
```

Note that floating components do not always require "anchor
positioning", so `floatingStyles` can be ignored.

## Interaction hooks

Interaction hooks allow the open state to change, among other
functionality. Each interaction hook accepts the
`context{:.const}` object which gets returned from
`useFloating(){:js}` as their first argument:

```js /context/
import {
  useFloating,
  useInteractions,
  useHover,
  useFocus,
} from '@floating-ui/react';

// Inside your component
const {refs, context} = useFloating({
  open: isOpen,
  onOpenChange: setIsOpen,
});

const hover = useHover(context);
const focus = useFocus(context);

const {getReferenceProps, getFloatingProps} = useInteractions([
  hover,
  focus,
]);
```

The `useHover(){:js}` and `useFocus(){:js}` hooks set up effects
and return event handler props to change the open state, the
latter of which get merged by `useInteractions(){:js}` for
rendering.

This API enables each of the hooks to be fully tree-shakeable and
opt-in. The navigation bar on the left explains them in detail.

### Prop getters

The prop getters are used to add event handlers returned from the
interaction hooks, among other functionality, to the reference
and floating elements. When called, they return an object of
props like `onFocus{:.keyword}`.

```js
<>
  <button ref={refs.setReference} {...getReferenceProps()}>
    My button
  </button>
  <div
    ref={refs.setFloating}
    style={floatingStyles}
    {...getFloatingProps()}
  >
    My tooltip
  </div>
</>
```

All custom event listener props, such as `onClick{:.keyword}`,
`onKeyDown{:.keyword}` and more you pass to the element should be
specified inside the prop getter. They perform merging of their
own internal event listeners and your own without overwriting
them.

```js
// ❌ Your `onClick` can be overwritten:
<div
  onClick={() => {
    // Potentially overwritten by the props below.
  }}
  {...getReferenceProps()}
/>
```

```js
// ✅ Merging works inside `getReferenceProps()`:
<div
  {...getReferenceProps({
    onClick() {
      // Will not be overwritten.
    },
  })}
/>
```

You may find passing all props through the prop getter helps you
remember to prevent overriding event handlers, but is not
currently required unless the value is a function event handler
that starts with `on`.

### `getItemProps`

```js
const {getItemProps} = useInteractions([]);
```

This is an _optional_ prop getter that is only used when dealing
with a list inside your floating element (see
[`useListNavigation`](/docs/useListNavigation)).

## Open event

The `onOpenChange{:.function}` event callback is invoked with an
(optional) event as a second parameter:

```js /event/1-2
useFloating({
  onOpenChange(isOpen, event) {
    setIsOpen(isOpen);
    if (event) {
      // The event can be determined. This callback may be invoked
      // in an effect, so the event is not available.
    }
  },
});
```

Note that `onOpenChange{:.function}` is _not_ called if you
manually changed the open state via the `setIsOpen(){:js}`
setter. You can derive the event yourself in this case anyway.

## Data

The context object contains a data ref with some information
available.

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

useEffect(() => {
  console.log(context.dataRef.current);
}, [context]);
```

Currently, only one built-in value is set:

```js
interface ContextData {
  // Which event caused the floating element to open.
  openEvent?: Event;

  // Add support for custom data to pass around.
  [key: string]: any;
}
```

## Changing the positioning reference while retaining events

- `refs.setReference{:js}` element is **both** the events and
  position reference by default.
- `refs.setPositionReference{:js}` allows you to separate the
  position to another element (either real or virtual).

```js /refs.setPositionReference/
const {refs} = useFloating();

return (
  <>
    <button ref={refs.setReference} {...getReferenceProps()}>
      Event reference
    </button>
    <button ref={refs.setPositionReference}>
      Position reference
    </button>
  </>
);
```

[View on CodeSandbox](https://codesandbox.io/s/xenodochial-butterfly-1xtup0?file=/src/App.tsx)

## Multiple floating elements on a single reference element

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

Refs can be merged with the [`useMergeRefs`](/docs/useMergeRefs)
hook, and props can be merged by calling one of the getters
inside of the other:

```js {9-12}
const {refs: tooltipRefs} = useFloating();
const {refs: menuRefs} = useFloating();

const {getReferenceProps: getTooltipReferenceProps} =
  useInteractions([]);
const {getReferenceProps: getMenuReferenceProps} =
  useInteractions([]);

const ref = useMergeRefs([
  tooltipRefs.setReference,
  menuRefs.setReference,
]);
const props = getTooltipReferenceProps(getMenuReferenceProps());

return (
  <button ref={ref} {...props}>
    Common reference
  </button>
);
```

[View on CodeSandbox](https://codesandbox.io/s/trusting-mendeleev-49qn11?file=/src/App.tsx)

## Disabled elements

Disabled elements don't fire events, so tooltips attached to
disabled buttons don't show. Avoid using the
`disabled{:.keyword}` prop, and make the button visually disabled
instead. This ensures you won't need any wrapper tags and makes
the tooltip accessible to all users.

[View on CodeSandbox](https://codesandbox.io/s/focused-feistel-0q6v43?file=/src/App.tsx)
