--- title: Keyboard Navigation Support impact: HIGH impactDescription: Critical for keyboard-only users tags: accessibility, a11y, keyboard, focus-management --- ## Keyboard Navigation Support Ensure all interactive elements are keyboard accessible and focus management is handled properly, especially in modals and dynamic content. **Incorrect (no keyboard support):** ```glimmer-js // app/components/dropdown.gjs ``` **Correct (full keyboard support with custom modifier):** ```javascript // app/modifiers/focus-first.js import { modifier } from 'ember-modifier'; export default modifier((element, [selector = 'button']) => { // Focus first matching element when modifier runs element.querySelector(selector)?.focus(); }); ``` ```glimmer-js // app/components/dropdown.gjs import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; import { fn } from '@ember/helper'; import focusFirst from '../modifiers/focus-first'; class Dropdown extends Component { @tracked isOpen = false; @action toggleMenu() { this.isOpen = !this.isOpen; } @action handleButtonKeyDown(event) { if (event.key === 'ArrowDown') { event.preventDefault(); this.isOpen = true; } } @action handleMenuKeyDown(event) { if (event.key === 'Escape') { this.isOpen = false; // Return focus to button event.target.closest('.dropdown').querySelector('button').focus(); } // Handle arrow key navigation between menu items if (event.key === 'ArrowDown' || event.key === 'ArrowUp') { event.preventDefault(); this.moveFocus(event.key === 'ArrowDown' ? 1 : -1); } } moveFocus(direction) { const items = Array.from(document.querySelectorAll('[role="menuitem"] button')); const currentIndex = items.indexOf(document.activeElement); const nextIndex = (currentIndex + direction + items.length) % items.length; items[nextIndex]?.focus(); } @action selectOption(value) { this.args.onSelect?.(value); this.isOpen = false; } } ``` **For focus trapping in modals, use ember-focus-trap:** ```bash ember install ember-focus-trap ``` ```glimmer-js // app/components/modal.gjs import FocusTrap from 'ember-focus-trap/components/focus-trap'; ``` **Alternative: Use libraries for keyboard support:** For complex keyboard interactions, consider using libraries that abstract keyboard support patterns: ```bash npm install @fluentui/keyboard-keys ``` Or use [tabster](https://tabster.io/) for comprehensive keyboard navigation management including focus trapping, arrow key navigation, and modalizers. Proper keyboard navigation ensures all users can interact with your application effectively. Reference: [Ember Accessibility - Keyboard](https://guides.emberjs.com/release/accessibility/keyboard/)