Как зациклить перемещение по элементам с помощью Tab в пределах определенной группы элементов?
================================================================================================

 Настраиваю доступность с клавиатуры в проекте на Angular 11.  

  

Есть такой сценарий использования, когда при нажатию на картинку появляется увеличенная во все окно картинка и по бокам стрелки вправо и влево, чтобы пролистать другие картинки (если они есть), кнопка закрытия этого просмотра и кнопка загрузки дополнительной картинки в эту карусель и удаления картинки.  

Область, которая не заполнена картинкой или кнопками, т.е. фон - просто цвет, затемняющий перекрытый интерфейс.  

  

При нажатию на "маленькую" картинку вызывается дополнительный Angular компонент, в котором как раз и отображается карусель с некоторыми кнопками. Эта карусель появляется поверх всех элементов.  

Я сделал так, чтобы при ngAfterViewInit фокус в этой каруселе появлялся на нужной мне кнопке.  

  

Проблема в том, что если нажимать Tab, то когда закончатся в этом компоненте элементы, на которых можно сфокусироваться, то дальше буду фокусироваться элементы, которые находятся "под" каруселью, т.е. будут фокусироваться элементы, перекрытого каруселью интерфейса.  

  

Это, на мой взгляд, нелогичное поведение и я хочу, чтобы табом можно было перемещаться по элементам только в появившейся карусели, которая является отдельным Angular компонентом. Как это сделать? 

 Слушать Tab и отключить дефолтное поведение 

 Я вот так реализовал в моем компоненте это циклическое перемещение с помощью Tab'а  

```
/** удержание фокуса внутри шаблона компонента */
  @HostListener('document:keydown', ['$event'])
  public tabCycle(event: KeyboardEvent): void {
    // выделенный элемент в шаблоне
    this.lastestFocused = event.target as HTMLElement;
    // крайний первый элемент, такая конструкция нужна потому что стрелка влево может быть скрыта
    const firstEdge = this.firstElement ? this.firstElement : this.secondElement;
    // флаг того, что выделенный элемент находится внутри шаблона компонента
    let isElementInsideComponent: boolean;

    // если это первый граничный элемент и мы пытаемся выделить элемент вне шаблона компонента
    if (this.lastestFocused.isEqualNode(firstEdge.nativeElement) && event.shiftKey && event.code === 'Tab') {
      event.preventDefault();
      this.lastElement.nativeElement.focus();
      return;
    }

    // если это последний граничный элемент и мы пытаемся выделить элемент вне шаблона компонента
    if (this.lastestFocused.isEqualNode(this.lastElement.nativeElement) && !event.shiftKey && event.code === 'Tab') {
      event.preventDefault();
      firstEdge.nativeElement.focus();
      return;
    }

    // если это не один из граничных элементов
    // определяем, что выделенный элемент находится внутри шаблона компонента
    event.composedPath().forEach((item: HTMLElement) => {
      if (item.tagName && item.tagName.toLowerCase() === this.host.nativeElement.tagName.toLowerCase()) {
        isElementInsideComponent = true;
      }
    });

    // если выделенный элемент вне шаблона компонента, то переводим фокус на первый граничный элемент
    if (!isElementInsideComponent) {
      firstEdge.nativeElement.focus();
    }
  }
```
  

  

Если убрать фокусировку в первых двух if'ах, то цикличности не будет, фокус будет просто останавливаться на граничных элементах.  

  

Надеюсь кому-то этот код поможет.