Keyboard navigation helps users move through your app using only the keyboard. This makes your app easier to use for everyone, especially people who cannot use a mouse.
Keyboard navigation support in Angular
Start learning this pattern below
Jump into concepts and practice - no test required
import { Component, HostListener } from '@angular/core'; @Component({ selector: 'app-keyboard-nav', template: ` <div tabindex="0" (keydown)="onKeydown($event)"> Press arrow keys to navigate </div> ` }) export class KeyboardNavComponent { @HostListener('keydown', ['$event']) onKeydown(event: KeyboardEvent) { switch(event.key) { case 'ArrowUp': // move focus up break; case 'ArrowDown': // move focus down break; // add more keys as needed } } }
Use tabindex="0" to make elements focusable by keyboard.
Use @HostListener('keydown') to listen for keyboard events in Angular.
<div tabindex="0" (keydown)="onKeydown($event)">Focusable div</div>
onKeydown(event: KeyboardEvent) {
if(event.key === 'Enter') {
console.log('Enter pressed');
}
}@HostListener('keydown', ['$event']) onKeydown(event: KeyboardEvent) { if(event.key === 'Tab') { // custom tab behavior } }
This component shows a list of items. You can use the up and down arrow keys to move focus between items. The focused item is highlighted with keyboard focus.
import { Component, ElementRef, ViewChildren, QueryList, AfterViewInit, HostListener } from '@angular/core'; @Component({ selector: 'app-keyboard-navigation', template: ` <ul> <li #items tabindex="0" *ngFor="let item of itemsList; let i = index" [attr.aria-selected]="i === focusedIndex"> {{item}} </li> </ul> ` }) export class KeyboardNavigationComponent implements AfterViewInit { itemsList = ['Item 1', 'Item 2', 'Item 3', 'Item 4']; focusedIndex = 0; @ViewChildren('items', {read: ElementRef}) items!: QueryList<ElementRef>; ngAfterViewInit() { this.focusItem(this.focusedIndex); } @HostListener('keydown', ['$event']) onKeydown(event: KeyboardEvent) { if(event.key === 'ArrowDown') { this.focusedIndex = (this.focusedIndex + 1) % this.itemsList.length; this.focusItem(this.focusedIndex); event.preventDefault(); } else if(event.key === 'ArrowUp') { this.focusedIndex = (this.focusedIndex - 1 + this.itemsList.length) % this.itemsList.length; this.focusItem(this.focusedIndex); event.preventDefault(); } } focusItem(index: number) { const element = this.items.toArray()[index].nativeElement as HTMLElement; element.focus(); } }
Always add tabindex="0" to elements you want keyboard users to focus.
Use event.preventDefault() to stop default scrolling when handling arrow keys.
Use ARIA attributes like aria-selected to improve screen reader support.
Keyboard navigation lets users move through UI with keys like arrows and tab.
Use tabindex to make elements focusable and @HostListener to handle key events.
Test keyboard navigation to ensure your app is accessible and easy to use.
Practice
Solution
Step 1: Understand keyboard navigation
Keyboard navigation lets users move through app elements using keys like arrows or tab.Step 2: Identify the purpose in Angular apps
Adding keyboard navigation improves accessibility and user experience by enabling key-based movement.Final Answer:
To allow users to navigate the app using keyboard keys -> Option AQuick Check:
Keyboard navigation = user key movement [OK]
- Confusing keyboard navigation with app speed
- Thinking it changes colors or animations
- Assuming it only works with mouse clicks
Solution
Step 1: Recall Angular event binding syntax
Angular uses parentheses for events and lowercase event names with dots for key names.Step 2: Match correct key event syntax
The correct syntax is (keydown.arrowdown) with lowercase and dot notation.Final Answer:
<button (keydown.arrowdown)="onArrowDown()">Click</button> -> Option BQuick Check:
Angular key event = (keydown.arrowdown) [OK]
- Using uppercase letters in event names
- Replacing dot with dash or camelCase
- Missing parentheses around event
<button #btn1 (keydown.arrowdown)="focusNext(1)">One</button> <button #btn2 (keydown.arrowdown)="focusNext(2)">Two</button> <button #btn3>Three</button>
Assuming focusNext(index) sets focus to the button at that index, which button gets focused after pressing 'ArrowDown' on button 1?
Solution
Step 1: Understand the event binding
Pressing 'ArrowDown' on button 1 triggers focusNext(1), which focuses button at index 1 (button 2).Step 2: Identify which button is at index 1
Button Two is the second button, so it receives focus.Final Answer:
Button Two -> Option CQuick Check:
ArrowDown on btn1 focuses btn2 [OK]
- Assuming index starts at 0 instead of 1
- Thinking focus stays on the same button
- Confusing button labels with indexes
@ViewChildren('btn') buttons: QueryList<ElementRef>;
focusNext(index: number) {
this.buttons.toArray()[index].nativeElement.focus;
}What is the error preventing focus from moving?
Solution
Step 1: Check method call syntax
The code uses nativeElement.focus without parentheses, so the focus method is not called.Step 2: Understand method invocation
To move focus, focus() must be called with parentheses to execute it.Final Answer:
Missing parentheses after focus method call -> Option DQuick Check:
Call focus() with () to move focus [OK]
- Forgetting parentheses on method calls
- Confusing @ViewChild and @ViewChildren usage
- Assuming toArray() is invalid on QueryList
Solution
Step 1: Understand Angular focus management
@ViewChildren collects all buttons, allowing indexed access to manage focus programmatically.Step 2: Handle keydown events with wrapping logic
Using keydown handlers for ArrowUp and ArrowDown with index checks lets you move focus up/down and wrap from last to first or first to last.Step 3: Compare options for correctness
Use @ViewChildren to get buttons, then in keydown handlers call focusNext(index) or focusPrev(index) with checks to wrap focus from last to first and vice versa uses Angular patterns and handles edge cases correctly. Others miss index checks or Angular integration.Final Answer:
Use @ViewChildren to get buttons, then in keydown handlers call focusNext(index) or focusPrev(index) with checks to wrap focus from last to first and vice versa -> Option AQuick Check:
Indexed focus with wrapping = correct keyboard navigation [OK]
- Not handling focus wrap at list ends
- Using @ViewChild for multiple elements incorrectly
- Ignoring Angular event bindings and using native listeners
