DEV Community

Cover image for Autofocus on Angular Form Field
nightwolfdev
nightwolfdev

Posted on • Edited on • Originally published at nightwolf.dev

Autofocus on Angular Form Field

Autofocus is a simple HTML attribute, but doesn’t work as expected with Angular apps. Let’s learn why with some different approaches to solve the problem!

Autofocus Attribute

Add the autofocus attribute to an Angular input form field.

<input type="text" id="firstName" name="firstName" formControlName="firstName" autofocus>
Enter fullscreen mode Exit fullscreen mode

If you refresh the page, you will see that the form field has focus. Problem solved right?! Not so fast!

Try starting on a different page first and then navigating to the page with the form. The field has no focus. What happened?

Autofocus happens as soon as the page is loaded. An Angular application is a single page application (SPA). Once that single page is loaded, that’s it! You’ve lost your chance to bring focus to any future navigation to other pages.

So what can we do? Read on!

Template Variable

Create a template variable on the input field called firstNameField. Remember that template variables are prefixed with a pound sign.

<input type="text" id="firstName" name="firstName" formControlName="firstName" #firstNameField>
Enter fullscreen mode Exit fullscreen mode

Within the component, you’ll need to import the following:

import { AfterViewInit, ElementRef, ViewChild } from '@angular/core';
Enter fullscreen mode Exit fullscreen mode

We want to access the input field from the view. We can use ViewChild and reference the template variable we previously created called firstNameField. Then give it a name also called firstNameField, though it doesn’t have to be. We’ll define it’s type to be ElementRef, specifically an HTML input element.

@ViewChild('firstNameField') firstNameField: ElementRef<HTMLInputElement>;
Enter fullscreen mode Exit fullscreen mode

Your first thought might be to do something within the OnInit lifecycle hook. For this particular scenario, that won’t work. We need to make sure the form field exists on the page before trying to do anything with it. For that we need the AfterViewInit lifecycle hook.

Make sure to implement AfterViewInit on your component.

export class ExampleComponent implements AfterViewInit, OnInit {
  ...
}
Enter fullscreen mode Exit fullscreen mode

Within the ngAfterViewInit lifecycle hook, let’s access the underlying native element and call the focus function.

ngAfterViewInit() {
  this.firstNameField.nativeElement.focus();
}
Enter fullscreen mode Exit fullscreen mode

Try starting on a different page first and then navigating to the page with the form. The form field now has focus!

Now imagine you had other form fields where you wanted to do this same thing. It gets a little repetitive doing the above changes for each component. That’s where an Angular directive can help!

Autofocus Directive

Create the following directive.

import { AfterViewInit, Directive, ElementRef } from '@angular/core';

@Directive({
  selector: '[appAutofocus]'
})
export class AutofocusDirective implements AfterViewInit {
  constructor(private element: ElementRef<HTMLInputElement>) { }

  ngAfterViewInit(): void {
    this.element.nativeElement.focus();
  }
}
Enter fullscreen mode Exit fullscreen mode

We’re doing something similar here like we did in the component. We use the AfterViewInit lifecycle hook to bring focus to the element.

To make this directive usable across any module, let’s create it as its own module so it can be imported into any module where it’s needed.

import { NgModule } from '@angular/core';

import { AutofocusDirective } from './autofocus.directive';

@NgModule({
  declarations: [AutofocusDirective],
  exports: [AutofocusDirective]
})
export class AutofocusDirectiveModule { }
Enter fullscreen mode Exit fullscreen mode

To use the directive, first import it into the module where you want to use it.

import { AutofocusDirectiveModule } from 'path/to/autofocus.directive.module';

@NgModule({
  ...
  imports: [
    ...
    AutofocusDirectiveModule,
    ...
  ]
})
export class ExampleModule { }
Enter fullscreen mode Exit fullscreen mode

Add the directive attribute, which is called appAutofocus, to the input field.

<input type="text" id="firstName" name="firstName" formControlName="firstName" appAutofocus>
Enter fullscreen mode Exit fullscreen mode

Instead of doing the steps outlined in the prior Template Variable section, you can now reuse this directive wherever you need to add focus to a form field!


Visit our website at https://nightwolf.dev and follow us on Twitter!

Top comments (0)