Keyboard navigation and focus management

Maya Patel Jan 2026
2 tabs
import { useEffect } from 'react'

interface KeyboardHandlers {
  [key: string]: () => void
}

export function useKeyboard(handlers: KeyboardHandlers, enabled = true) {
  useEffect(() => {
    if (!enabled) return

    const handleKeyDown = (e: KeyboardEvent) => {
      const handler = handlers[e.key]
      if (handler) {
        e.preventDefault()
        handler()
      }
    }

    window.addEventListener('keydown', handleKeyDown)
    return () => window.removeEventListener('keydown', handleKeyDown)
  }, [handlers, enabled])
}
2 files · typescript Explain with highlit

Accessible apps support keyboard-only navigation with proper focus management. Tab order should follow visual order, and all interactive elements must be keyboard accessible. I use tabIndex={0} to make custom controls focusable and tabIndex={-1} for programmatic focus without tab stops. Arrow keys navigate menus and lists using useKeyboard hooks. Focus moves to opened modals, traps inside them, and returns to the trigger on close. Skip links let keyboard users bypass navigation. The :focus-visible pseudo-class shows focus rings only for keyboard navigation, not mouse clicks. ARIA attributes like aria-label and role provide context for screen readers. Testing with keyboard-only navigation catches most accessibility issues.