htmlangulartypescripttabindex

Setting focus on first element of list item on HTML + Angular will focus the second one instead


I have been working on a requirement for an UI, as soon as the tab key is pressed for the first time, I need to set up the focus on the first element of a list item that is constructed with an array of objects. Next times I press tab key, I need to go over the list items and if I reach the end of the list, I go back to the first element.

Actually I achieved my goal partially, the problem I am facing is that as soon as I press the tab key for the first time, it focus the second list item instead of the first one and as soon as I reach the end of the list and I hit tab, it will focus the second one, it always skip the first list item, but not sure why.

This is the HTML code of the component:

<div class="row">
  <div class="col-md-12">
    <div class="grandparent">
      <div class="parent">
        <ul #optionsTypeMenu>
          <li *ngFor="let option of options; let i = index; last as isLast" (click)="open(option)" tabindex="0" id="{{option.name}}">
            <div class="event-badge-block"
              [ngClass]="{ 'select': isSubmitted, 
                            'disabled': optionSelectionDisabled(option, isLast) }">
              <small class="bagde">{{ i + 1 }}</small>
              <div class="option-label">
                <span>{{ option.name}}
                </span>
              </div>
            </div>
          </li>
        </ul>
      </div>
    </div>
  </div>
</div>

And this is the code for the tab key:

@HostListener('document:keydown.tab') focusOptionFindingsSection(event: KeyboardEvent) {
        let activeElement = document.activeElement;
        let isCurrentFocusedElementTabable = this.optionsTypeMenu.nativeElement.contains(activeElement);

        if (!isCurrentFocusedElementTabable || this.CURR_TAB_INDEX == this.options.length - 1) {
            this.CURR_TAB_INDEX = 0;
        }

        if (this.CURR_TAB_INDEX == 0) {
            this.optionsTypeMenu.nativeElement.children[this.CURR_TAB_INDEX].focus();
        }

        this.CURR_TAB_INDEX++;
    }

I have been debugging and trying to force the focus with document.getElementById... but I got the same result. I was wondering if there is something I could have missed, not sure if tabindex could be the reason, but any clue or help is highly appreciated. Thanks in advance.

As requested, I created a Stackblitz: https://stackblitz.com/edit/get-data-and-display-in-ul-and-li-hbg7xj?file=src%2Fapp%2Fapp.component.ts


Solution

  • @Amenawon is right in the fact that the issue here is that you are triggering focus event twice.

    Once from this.optionsTypeMenu.nativeElement.children[0].focus(); and the second being the default event from the tab key.

    To do this properly prevent this in angular we need to specify what key to listen to, and what arguments to pass to the listener

    like so @HostListener('document:keydown.tab', ['$event'])

    That's why your event argument was undefined

    see full fix here on stackblitz