Setting focus in Angular 2

Setting focus in Angular 2 requires working with native DOM elements. While this is possible, the documentation recommends against doing so. But making ARIA widgets keyboard accessible requires focus management. So it looks like we have a choice between two APIs, ElementRef and Renderer.

First we will look at ElementRef. At this time, it is designated as stable but also a security risk as seen below.

Elementref is stable but also a security risk

Permitting direct access to the DOM can make your application more vulnerable to XSS attacks. Carefully review any use of ElementRef in your code.

The built-in browser DOM APIs do not automatically protect you from security vulnerabilities. For example, document, the node available through ElementRef, and many third-party APIs contain unsafe methods. Avoid directly interacting with the DOM and instead use Angular templates where possible.

The documentation also says to use this API as a last resort as below as seen below.

Use this API as the last resort when direct access to DOM is needed. Use templating and data-binding provided by Angular instead. Alternatively you take a look at Renderer which provides API that can safely be used even when direct access to native elements is not supported.
Relying on direct DOM access creates tight coupling between your application and rendering layers which will make it impossible to separate the two and deploy your application into a web worker.

But unfortunately, Angular 2’s template syntax does not offer a method to set focus on a given element at this time. As ARIA developers, we need some way to do this. Now lets look at Renderer.

As previously seen in the excerpts from Angular 2’s documentation, Renderer is considered to be the safer choice of the two, but it is currently designated as experimental.

Renderer is experimental at this time

Despite the experimental status, I am using Renderer in https://github.com/clane/A2A11yQuickstart. I’ve tested setting focus using the Renderer API in the following operating systems and browsers.

OSX 10.11.2

  • Chrome Version 55.0.2883.95 (64-bit)
  • Firefox 51.0.1 (64-bit)
  • Safari Version 9.0.2 (11601.3.9)

Windows 7

  • IE 11
  • Firefox 45.4.0
  • Chrome Version 55.0.2883.87 m (64-bit

Here is example of using Renderer from A2 A11y Quickstart

export class ModalOpenButton {

constructor(private renderer: Renderer, private titleService: Title ) {}
@ViewChild('modalOpen') openButton: any;
@Output() onOpenButtonActivated = new EventEmitter();

open(){
this.onOpenButtonActivated.emit(true);
this.titleService.setTitle('MODAL TIME');
}

focusMe(){
this.renderer.invokeElementMethod(this.openButton.nativeElement, 'focus');
}

}

Although I cannot predict if Renderer will shed it’s experimental status I recommend using it instead of ElementRef and keeping an eye on it’s status.