简体   繁体   中英

Ionic/Angular: Can't Focus on HTMLElement with Screen Reader

I am attempting to force a screen reader in Ionic 5 to focus on and announce an element.

My template element:

    <ion-title tabindex="-1" #title id="title" role="heading" aria-level="1" class="title">My Title</ion-title>

I have attempted to access the element via document and as a Viewchild:

    @ViewChild('title', { read: ElementRef }) title: ElementRef;
    const title: any = document.getElementById('title');

I attempt to focus after a delay with this test:


    ionViewWillEnter(): void {
        setTimeout(() => {
          const title: any = document.getElementById('title');
          if (title) {
            title.focus();
          }
        }, 3000);
    
        setTimeout(() => {
          this.title.nativeElement.focus();
        }, 5000);
      }

Neither of these focus, however. The screen reader does not announce the title in either Android nor iOS.

Update

Just to clarify, I need the screen reader position to move to a specified element. Focusing on an element as described will not move the screen reader position.

Any help would be appreciated, here's my Ionic info:

 Ionic CLI                     : 5.4.16
   Ionic Framework               : @ionic/angular 5.5.3
   @angular-devkit/build-angular : 0.901.15
   @angular-devkit/schematics    : 9.1.15
   @angular/cli                  : 9.1.15
   @ionic/angular-toolkit        : 2.3.3

Capacitor:

   Capacitor CLI   : 2.4.2
   @capacitor/core : 2.4.0

I created a BasePage for all the Ionic pages to extend. It captures the active element on click and focus events and focuses on that element when the page enters again.

It also automatically attempts to find the ion-title and focus on that if there is no previously active element to focus.

This should cover the basic needs. You can tweak add timeouts to the focus method

import { Component, ElementRef, HostListener } from '@angular/core';
import { ViewDidEnter } from '@ionic/angular';
import { isNullOrUndefined } from 'util';

@Component({
  template: ''
})
export class BasePage implements ViewDidEnter {
  private _previouslyActiveElement: HTMLElement;

  constructor(protected elementRef: ElementRef) {}

  ionViewDidEnter() {
    if (!isNullOrUndefined(this._previouslyActiveElement)) {
      this.focusOnElement(this._previouslyActiveElement);
    } else {
      if (
        !isNullOrUndefined(this.elementRef.nativeElement) &&
        this.elementRef.nativeElement.querySelectorAll('[autofocus]').length === 0) {
        const initialFocusElement: HTMLElement = <HTMLElement>this.elementRef.nativeElement.getElementsByTagName('ion-title')[0];

        if (!isNullOrUndefined(initialFocusElement)) {
          this.focusOnElement(initialFocusElement);
        }
      }
    }
  }

  @HostListener('focusin', ['$event.target'])
  @HostListener('click', ['$event.target'])
  capturePreviouslyActiveElement(element: HTMLElement) {
    this._previouslyActiveElement = element;
  }

  focusOnElement(element: HTMLElement): void {
    if (isNullOrUndefined(element)) {
      return;
    }

    try {
      // Make sure it's focusable
      if (isNullOrUndefined(element.getAttribute('tabindex'))) {
        element.setAttribute('tabindex', '-1');
      }

      element.focus();
    } catch (err) {
      console.log('error handling aria focus ' + err);
    }
  }
}

I have created stackblitz . And it all works as expected. To make it more visible Ive added style

:focus {
  outline: 3px solid orange;
}

Also I would recommend you to add aria-label since ion-title is element with div inside and I am not sure if all readers are handling that

  <ion-title tabindex="-1" #title id="title" role="heading" aria-level="1" class="title" role="heading"
      aria-label="What you want to read">My Title
    </ion-title>

And lastly since you are using angular with your ionic app, you can have a look into material library which has live announcer

@Component({...})
export class MyComponent {

 constructor(liveAnnouncer: LiveAnnouncer) {
   liveAnnouncer.announce("Hey Google");
 }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM