useListNavigation
Adds focus-managed indexed navigation via arrow keys to a list of items within the floating element.
import {
useFloating,
useInteractions,
useListNavigation,
} from '@floating-ui/react-dom-interactions';
// ...
const {context} = useFloating();
const {getReferenceProps, getFloatingProps, getItemProps} =
useInteractions([
useListNavigation(context, {
// props
}),
]);
Spread the getItemProps
to each list item.
Props
interface Props {
listRef: React.MutableRefObject<Array<HTMLElement | null>>;
activeIndex: number | null;
onNavigate: (index: number | null) => void;
enabled?: boolean;
selectedIndex?: number | null;
loop?: boolean;
nested?: boolean;
rtl?: boolean;
virtual?: boolean;
allowEscape?: boolean;
orientation?: 'vertical' | 'horizontal' | 'both';
focusItemOnOpen?: 'auto' | boolean;
focusItemOnHover?: boolean;
}
listRef
default: empty list
A ref that holds an array of list items. You can assign each item in the array by its index like so:
const options = ['one', 'two', 'three'];
const listRef = useRef([]);
return options.map((option, index) => (
<li
key={option}
ref={(node) => {
listRef.current[index] = node;
}}
>
{option}
</li>
));
activeIndex
default: null
The currently active item index, which may or may not be selected.
In a <Select />
, this is the item that's currently
highlighted (focused) but not selected. The user may have intent
to select this item.
onNavigate
default: noop
Callback invoked when the user navigates, passed in the current
activeIndex
.
const [activeIndex, setActiveIndex] = useState(null);
useListNavigation(context, {
onNavigate: setActiveIndex,
});
enabled
default: true
Conditionally enable/disable the hook.
useListNavigation(context, {
enabled: false,
});
selectedIndex
default: null
The currently selected item index, which may or may not be active.
In a <Select />
, this is the item shown in the trigger
button.
loop
default: false
Whether to restart from the beginning or end if the user has navigated to the boundary of the list.
useListNavigation(context, {
loop: true,
});
nested
default: false
If the list is nested within another one (e.g. a nested submenu), the navigation semantics change.
useListNavigation(context, {
nested: true,
});
rtl
default: false
Whether the direction of the floating element's navigation is in RTL layout.
useListNavigation(context, {
rtl: true,
});
virtual
default: false
Whether the focus is virtual (using
aria-activedescendant
).
Use this if you need focus to remain on the reference element (such as an input), but allow arrow keys to navigate list items. This is common in autocomplete listbox components.
useListNavigation(context, {
virtual: true,
});
Your virtually-focused list items must have a unique
id
set on them.
allowEscape
Determines whether focus can escape the list, such that nothing is selected after navigating beyond the boundary of the list. In some autocomplete/combobox components, this may be desired, as screen readers will return to the input.
loop
must betrue
useListNavigation(context, {
loop: true,
allowEscape: true,
});
orientation
default: 'vertical'
The orientation in which navigation occurs.
useListNavigation(context, {
orientation: 'horizontal',
});
focusItemOnOpen
default: 'auto'
Whether to focus the item upon opening the floating element.
'auto'
infers what to do based on the input type (keyboard
vs. pointer), while a boolean value will force the value.
useListNavigation(context, {
focusItemOnOpen: true,
});
focusItemOnHover
default: true
Whether hovering an item synchronizes the focus.