Skip to content

React

A toolkit to position and create interactions for floating elements with React.

npm install @floating-ui/react

If you only need positioning without interactions, use the following for a smaller bundle size:

npm install @floating-ui/react-dom

Choose the package you installed for better docs:

The goal of this package is to provide primitives to create components for tooltips, popovers, dropdown menus, hover cards, modal dialogs, select menus, comboboxes, and more. Instead of providing any pre-built components, it gives you the tools to create them more easily. This is ideal if you want lots of control, but does require more work to get started. The full guides in React Examples contain some copy-pasteable examples to get you started more quickly.

Usage

Floating UI’s usage can be broken down into two disparate parts:

  • Positioning (available for both @floating-ui/react and @floating-ui/react-dom).
  • Interactions (available for just @floating-ui/react).

Positioning

useFloating() is the main hook of each package.

At its most basic, the Hook returns a refs object and a floatingStyles object:

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 is the reference (or anchor) element that is being referred to for positioning.
  • refs.setFloating is the floating element that is being positioned relative to the reference element.
  • floatingStyles is an object of positioning styles to apply to the floating element’s style 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.

Anchoring

To ensure the floating element remains anchored to the reference element, such as when scrolling or resizing, pass autoUpdate to the whileElementsMounted option:

const {refs, floatingStyles} = useFloating({
  whileElementsMounted: autoUpdate,
});

API docs

Visit the full useFloating API docs for detailed information about customizing the positioning of floating elements.

Testing

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

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:

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

Narrow reference type

Due to virtual elements, you may need to narrow the type when performing DOM operations on the ref:

Interactions

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 — a boolean that represents whether the floating element is currently rendered.
  • onOpenChange — an event callback invoked when the open boolean state should change.
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.

Hooks

Interaction Hooks allow the open state to change, among other functionality. Each interaction Hook accepts the context object which gets returned from useFloating() as their first argument:

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() and useFocus() Hooks set up Effects and return event handler props to change the open state, the latter of which get merged by useInteractions() 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.

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

Open event callback

The onOpenChange event callback is invoked with an optionally-defined event object and reason string as the second and third parameter:

useFloating({
  onOpenChange(isOpen, event, reason) {
    setIsOpen(isOpen);
    event && console.log(event);
    reason && console.log(reason);
  },
});

Note that onOpenChange is not called if you manually changed the open state via the setIsOpen() setter. You can derive the event yourself in this case anyway.

Changing the positioning reference while retaining events

  • refs.setReference element is both the events and position reference by default.
  • refs.setPositionReference allows you to separate the position to another element (either real or virtual).
const {refs} = useFloating();
 
return (
  <>
    <button ref={refs.setReference} {...getReferenceProps()}>
      Event reference
    </button>
    <button ref={refs.setPositionReference}>
      Position reference
    </button>
  </>
);

View on CodeSandbox

Multiple floating elements on a single reference element

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

Refs can be merged with the useMergeRefs hook, and props can be merged by calling one of the getters inside of the other:

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

Disabled elements

Disabled elements don’t fire events, so tooltips attached to disabled buttons don’t show. Avoid using the disabled 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