Skip to content

FloatingFocusManager

Provides flexible modal or non-modal focus management for a floating element. Modal behavior is the default — focus is fully trapped inside the floating element while it is rendered.

This component should only be rendered when the floating element is open and directly wrap it.

import {FloatingFocusManager} from '@floating-ui/react';
 
function App() {
  const {context} = useFloating();
 
  return (
    <>
      {/* reference element */}
      {isOpen && (
        <FloatingFocusManager context={context}>
          {/* floating element */}
        </FloatingFocusManager>
      )}
    </>
  );
}
import {FloatingFocusManager} from '@floating-ui/react';
 
function App() {
  const {context} = useFloating();
 
  return (
    <>
      {/* reference element */}
      {isOpen && (
        <FloatingFocusManager context={context}>
          {/* floating element */}
        </FloatingFocusManager>
      )}
    </>
  );
}

Props

interface Props {
  context: FloatingContext;
  disabled?: boolean;
  order?: Array<'reference' | 'floating' | 'content'>;
  initialFocus?:
    | number
    | React.MutableRefObject<HTMLElement | null>;
  returnFocus?: boolean;
  guards?: boolean;
  modal?: boolean;
  visuallyHiddenDismiss?: boolean | string;
  closeOnFocusOut?: boolean;
}
interface Props {
  context: FloatingContext;
  disabled?: boolean;
  order?: Array<'reference' | 'floating' | 'content'>;
  initialFocus?:
    | number
    | React.MutableRefObject<HTMLElement | null>;
  returnFocus?: boolean;
  guards?: boolean;
  modal?: boolean;
  visuallyHiddenDismiss?: boolean | string;
  closeOnFocusOut?: boolean;
}

context

Required

The contextcontext object returned from useFloating()useFloating().

<FloatingFocusManager context={context}>
  {/* floating element */}
</FloatingFocusManager>
<FloatingFocusManager context={context}>
  {/* floating element */}
</FloatingFocusManager>

disabled

default: falsefalse

Disables all focus management entirely. Useful to delay focus management until after a transition completes or some other conditional state.

<FloatingFocusManager context={context} disabled>
  {/* floating element */}
</FloatingFocusManager>
<FloatingFocusManager context={context} disabled>
  {/* floating element */}
</FloatingFocusManager>

order

default: ['content']['content']

The order in which focus cycles.

<FloatingFocusManager
  context={context}
  // Initially focuses the floating element. Subsequent tabs
  // will cycle through the tabbable contents of the floating
  // element.
  order={['floating', 'content']}
  // Keeps focus on the reference element. Subsequent tabs
  // will cycle through the tabbable contents of the floating
  // element.
  order={['reference', 'content']}
>
  {/* floating element */}
</FloatingFocusManager>
<FloatingFocusManager
  context={context}
  // Initially focuses the floating element. Subsequent tabs
  // will cycle through the tabbable contents of the floating
  // element.
  order={['floating', 'content']}
  // Keeps focus on the reference element. Subsequent tabs
  // will cycle through the tabbable contents of the floating
  // element.
  order={['reference', 'content']}
>
  {/* floating element */}
</FloatingFocusManager>

initialFocus

default: 00

Which element to initially focus. Can be either a number (tabbable index as specified by the orderorder) or a ref.

<FloatingFocusManager
  context={context}
  initialFocus={elementRef}
>
  {/* floating element */}
</FloatingFocusManager>
<FloatingFocusManager
  context={context}
  initialFocus={elementRef}
>
  {/* floating element */}
</FloatingFocusManager>

Negative number

You can set this to a negative number to ignore the initial focus. This is required to prevent conflicts if your floating element has no tabbable content and is instead controlled by the useListNavigation()useListNavigation() hook which has its own focus management.

<FloatingFocusManager context={context} initialFocus={-1}>
  {/* floating element */}
</FloatingFocusManager>
<FloatingFocusManager context={context} initialFocus={-1}>
  {/* floating element */}
</FloatingFocusManager>

If there is no list navigation, then modalmodal behavior’s focus trap will no longer work. To maintain the trap, you can place the initial focus on the floating element:

const {context, refs} = useFloating();
 
return (
  <FloatingFocusManager
    context={context}
    initialFocus={refs.floating}
  >
    {/* floating element */}
  </FloatingFocusManager>
);
const {context, refs} = useFloating();
 
return (
  <FloatingFocusManager
    context={context}
    initialFocus={refs.floating}
  >
    {/* floating element */}
  </FloatingFocusManager>
);

returnFocus

default: truetrue

Determines if focus should be returned to the reference element (or if that is not available, the previously focused element). This prop is ignored if the floating element lost focus.

<FloatingFocusManager context={context} returnFocus={false}>
  {/* floating element */}
</FloatingFocusManager>
<FloatingFocusManager context={context} returnFocus={false}>
  {/* floating element */}
</FloatingFocusManager>

guards

default: truetrue

Determines if the focus guards are rendered. If not, focus can escape into the address bar/console/browser UI, like in native dialogs.

<FloatingFocusManager context={context} guards={false}>
  {/* floating element */}
</FloatingFocusManager>
<FloatingFocusManager context={context} guards={false}>
  {/* floating element */}
</FloatingFocusManager>

default: truetrue

Determines if focus is “modal”, meaning focus is fully trapped inside the floating element and outside content cannot be accessed. This includes screen reader virtual cursors.

<FloatingFocusManager context={context} modal={false}>
  {/* floating element */}
</FloatingFocusManager>
<FloatingFocusManager context={context} modal={false}>
  {/* floating element */}
</FloatingFocusManager>

Non-modal behavior

The floating element should be rendered after the reference element in the React tree. It can be portalled however.

Ensure you have an explicit “close” button. This can be either visible to all users, or visually-hidden so it is only available to assistive tech (see visuallyHiddenDismiss). Touch-based screen readers often will not have an esc key available to dismiss the element, so an explicit close button is required, otherwise the user will be trapped in the floating element if they don’t want to select anything (thus needing to reload the page).

Comboboxes

The listbox part (floating element) of a combobox (input + listbox popup) can be portalled and accessible to touch screen readers when using modal focus management. DOM focus does not become modal but screen reader virtual cursors do become modal, allowing a touch screen reader to immediately access the portalled listbox items.

visuallyHiddenDismiss

default: falsefalse

If your focus management is modal and there is no explicit close button available, you can use this prop to render a visually-hidden dismiss button at the start and end of the floating element. This allows touch-based screen readers to escape the floating element due to lack of an esc key.

<FloatingFocusManager context={context} visuallyHiddenDismiss>
  {/* floating element */}
</FloatingFocusManager>
<FloatingFocusManager context={context} visuallyHiddenDismiss>
  {/* floating element */}
</FloatingFocusManager>

You can pass a string which will be announced by the screen reader, e.g. for languages other than English. The default string when using truetrue is DismissDismiss.

<FloatingFocusManager
  context={context}
  visuallyHiddenDismiss="Dismiss popup"
>
  {/* floating element */}
</FloatingFocusManager>
<FloatingFocusManager
  context={context}
  visuallyHiddenDismiss="Dismiss popup"
>
  {/* floating element */}
</FloatingFocusManager>

closeOnFocusOut

default: truetrue

Determines whether focusout event listeners that control whether the floating element should be closed if the focus moves outside of it are attached to the reference and floating elements. This mostly affects non-modal focus management.

<FloatingFocusManager context={context} closeOnFocusOut={false}>
  {/* floating element */}
</FloatingFocusManager>
<FloatingFocusManager context={context} closeOnFocusOut={false}>
  {/* floating element */}
</FloatingFocusManager>