Skip to content
TrademarkTrademark
Docs
Hooks

useArrowNavigation

Updated: February 22, 2026
View on GitHub

The useArrowNavigation hook provides keyboard navigation for interactive elements using arrow keys. It supports row, column, and grid layouts with customizable behavior.

Used in components: DropdownWrapper, EmojiPicker, Select, ContextMenu, MegaMenu

Most of the time you don't need to use this hook directly. Components like DropdownWrapper, Select, and MegaMenu already provide built-in keyboard navigation. Use this hook when building custom navigable interfaces that aren't covered by existing components.

Features

  • Arrow key navigation (up, down, left, right)
  • Support for row, column, and grid layouts
  • Automatic focus management
  • Enter/Space key selection
  • Optional wrapping at boundaries
  • Visual focus highlighting
  • ARIA-compliant accessibility

Basic usage

Add arrow navigation to a list:

Grid layout

Navigate a grid with arrow keys:

Row layout

Navigate horizontally:

When it takes focus

initialFocusedIndex says which item is current, not that focus should move there. The hook takes focus on its first pass only when autoFocus is set, or when nothing else holds it — the case right after a keyed remount, where the element that had focus has just been removed and focusing it again restores rather than steals. Every later pass follows a keystroke, so it always moves focus.

When it does take focus on that first pass and initialFocusedIndex is left at -1, it goes to the item marked aria-selected="true" — a native select opens on the value it is already showing, and a long list told from the top hides it. With no selection it starts at the first enabled item; a selected item that is disabled is skipped.

aria-selected is yours to author. Do not drive it from focusedIndex: that is what the hook's own data-highlighted and highlighted class are for, and conflating the two makes a screen reader announce whichever item the arrow keys have reached as the selected one.

API Reference

Type
Default
layout
'row''column''grid'
—
itemCount
number—
columns
number8
containerRef
RefObject<HTMLElement>—
onSelect
(index: number) => void—
onFocusChange
(index: number) => void—
wrap
booleantrue
initialFocusedIndex
number-1
itemSelector
string'[role="option"], [data-value], button'
autoFocus
booleanfalse
disabled
booleanfalse
disableHighlighting
booleanfalse

Return value

Keyboard controls

  • Arrow Up: Move focus up (column/grid)
  • Arrow Down: Move focus down (column/grid)
  • Arrow Left: Move focus left (row/grid)
  • Arrow Right: Move focus right (row/grid)
  • Enter/Space: Select focused item
  • Home: Focus first item
  • End: Focus last item

Styling focused items

Use the focusedIndex to style the focused item:

Accessibility

The hook automatically manages:

  • Focus visibility with visual indicators
  • ARIA roles and attributes
  • Keyboard event handling
  • Focus trap within container

For best accessibility, add appropriate ARIA attributes:

Used in components

This hook is used internally by:

  • EmojiPicker
  • Dropdown
  • Select
  • ContextMenu
  • MegaMenu
Edit this page on GitHub