Keyboard navigation on angular controls


One of the benefits of using Angular Material controls is that they come with built-in accessibility. As such, they include the role and aria-* attributes, as well as support for standard keyboard navigation. If you decide to create your own widgets, you will also need to consider accessibility, or you may lose some users. As an example, we recently transformed some HTML elements into a custom Angular 11 component, which we then have refactored in a multi-level drop-down list. In either case, our check did not include any accessibility features. As a result, screen readers had no way to identify the component as a menu or navigate its items on laptops and desktops without a mouse.

In this tutorial, we’ll address these limitations by making our original single-level drop-down list fully accessible.

Switch the menu to angular

Opening and closing the menu is the area of ​​the component that houses the drop-down menu component, aka, the parent. During this time, the drop-down menu component will handle keyboard navigation. As such, we can look at the two separately.

In the app.component.html model, we will add:

  1. the # menuTrigger model variable
  2. a tabindex attribute, for the menu to trigger a tabulation
  3. a down key Event Manager

Why down key for Angular menu events?

You might be wondering why I am binding our key manager to down key, as opposed to Press the key or touch? Of the three key events, I prefer down key because, unlike the Press the key event, the down key The event is raised for all keys, whether or not they produce a character value. Both down key and touch events provide a code indicating which key is pressed, while Press the key only indicates which character has been entered. Since we are not dealing with characters at all, Press the key is not the right event for us. Keyup is considered by many developers, including myself, as key pressed simple-minded brother. He always gets the message too late to do anything useful with it.

The onKeyDown () event handler

The three keys we will listen to are Escape, Enter, and Tongue. Here’s what we’ll do for each:

  • Escape: Close the menu and place the focus on the menu trigger.
  • Enter: Open the menu and place the focus on the first menu item.
  • Tongue: Close the menu (if it is open).

You can see the key manipulation in the onKeyDown () method of app.component.ts deposit:

public onKeyDown(event: KeyboardEvent) {

  switch (event.key) {

    case 'Escape':

      this.menuOpened = false;



    case 'Enter':

        this.menuOpened = true;

        // make sure that the menu is open before setting focus

        setTimeout(() => this.multiLevelDropDown.setFocusOnFirstMenuItem(), 1);


    case 'Tab':

      if (this.menuOpened) {

        this.menuOpened = false;





Referencing the menu trigger and drop-down menu component

Being a very savvy executive, Angular prescribes its own way of referencing DOM elements using the @ViewChild real estate decorator. I have seen many cases of document.getElementById (), document.getElementsByClassName (), etc., in angular applications. This is an anti-model because it breaks the component-based architecture of Angular. Here is the correct way to reference the # menuTrigger and Component Drop-down menu:

@ViewChild('menuTrigger', { read: ElementRef, static: true }) 

private menuTrigger : ElementRef;



private dropDownMenu : DropdownMenuComponent;

The first one @ViewChild refers to the SCOPE element to which we added the # menuTrigger model variable. Since this is only a normal HTML element and not a correct Angular component, we’ll read it as a ElementRef. the static: true The metadata property tells Angular that it is possible to resolve query results before change detection runs because the item is not dynamic.

The second @ViewChild refers to our drop-down menu as Component Drop-down menu class so that we can access its public members. Whenever you have only one component in a model, you can omit the model variable and directly reference the component.

Focus on the first menu item

The DropdownMenuComponent is well placed to place the focus on the first menu item because it has the MenuItemsRef reference to all of its menu items. the List of queries type provides the first and latest properties to facilitate access to these elements:

public setFocusOnFirstMenuItem(): void {

  if (this.menuItemsRef != null && this.menuItemsRef.first != null) {




We also need to update the CSS so that the active menu item is highlighted:


a:focus {

  background-color: #a12f42;


Navigate through menu items

We will use the up and down arrow keys to navigate between menu items. In the dropdown-menu.component.html template, we will add a tabindex -1 in order to deactivate the Tongue key as well as a down key manager, similar to that of AppComponent:

(click)="onClick($event, i)" (keydown)="onKeyDown($event, i)">

  {{ mi.icon }}

  {{ mi.value }}

In the onKeyDown () manager, we can access menu items by index and add or subtract 1 from the current index to move the focus to the next item. With a little extra effort, we can also allow menu navigation to return to the first or last item when there are no more items:

public onKeyDown(event: KeyboardEvent, index: number) {

  switch (event.key) {

    case "ArrowUp":


      (index === 0

         ? this.menuItemsRef.last 

         : this.menuItemsRef.get(index - 1)




    case "ArrowDown":


      (index === this.menuItemsRef.length - 1

        ? this.menuItemsRef.first 

        : this.menuItemsRef.get(index + 1)





The demo

At, you will find the demo with all the code that was presented in this article.


Making your own Angular controls is a perfectly valid alternative to hardware controls when you don’t want all the bells and whistles they provide, or you are looking for different behavior and / or appearance. The key is to provide the accessibility features that users expect in modern web applications.

Source link


About Author

Leave A Reply