2.0 alpha
These docs describe 2.0. Install it with @once-ui-system/core@alpha.
On 1.8.x? Read the 1.x docs
TrademarkTrademarkDocs
Ctrl k
Search docs...
Components

ArrowNavigation

Updated: August 31, 2026
View on GitHub
ArrowNavigation wraps a set of items and moves focus between them with the arrow keys. It is the component form of useArrowNavigation: the hook when you own the container and its key handler, this when you would rather not write either. Arrow keys are the expected way to move within a composite widget — a menu, a listbox, a toolbar, an emoji grid — where Tab should reach the widget once and then hand over. Select, DropdownWrapper, DatePicker and Kbar are built on it. layout decides which keys move focus:
  • "row" — Left and Right.
  • "column" — Up and Down.
  • "grid" — all four, with columns giving the row width so Up and Down step a whole row at a time.
wrap (on by default) carries focus from the last item back to the first. Turn it off for a list where hitting the end should feel like an end. Items are found with [role="option"], [data-value], button, [tabindex]:not([tabindex="-1"]). Override itemSelector when your items are none of those, and keep itemCount in step with what the selector actually matches — the count drives wrapping and the bounds, so a mismatch shows up as arrow keys that stop one item early. Set trapFocus to wrap the region in a FocusTrap. The two divide the keyboard cleanly: the trap owns Tab and Escape, ArrowNavigation owns the arrows. useArrowNavigationContext() returns the navigation state from inside the subtree, for an item that needs to know it is the focused one — to paint a highlight, or to scroll itself into view. Syncing setFocusedIndex from hover is worth doing: it keeps the keyboard highlight and the pointer from disagreeing about which item is current.
Prop
Type
Default
layout
Which arrow keys move focus. Required.
rowcolumngrid
itemCount
How many items the selector matches. Required.
number
columns
Row width for the grid layout.
number8
onSelect
Called on Enter or Space.
(index: number) => void
onFocusChange
Called whenever focus moves.
(index: number) => void
wrap
Carry focus from the last item to the first.
booleantrue
initialFocusedIndex
Index focused on mount. -1 means none.
number-1
itemSelector
How navigable children are found.
stringrole=option, data-value, button, tabindex
autoFocus
Focus the first item on mount.
booleanfalse
disabled
Stop handling keys.
booleanfalse
disableHighlighting
Skip applying the highlighted state to items.
booleanfalse
trapFocus
Wrap the region in a FocusTrap.
booleanfalse
focusTrapActive
Whether that trap is active.
booleantrue
onEscape
Escape handler, passed to the trap.
() => void
autoFocusTrap
Let the trap move focus in when it activates.
booleantrue
restoreFocus
Let the trap return focus when it deactivates.
booleantrue
role
ARIA role for the container, e.g. listbox or menu.
string
aria-label
string
children
React.ReactNode
className
string
style
React.CSSProperties
Edit this page on GitHub
TrademarkTrademark
Built with curiosity by Lorant One and the Design Engineers Club