This article has been updated to the latest version of Angular 8 and tested with Angular 7. The content is likely be applicable for older Angular 2 or other previous versions.

When dealing with required inputs on a form sometimes the user can miss a required field. When this happens, it can be confusing for users what needs to be resolved to continue in the form. With Angular Forms, we can help the user by focusing the first invalid input when they submit the form.

In this example form, we have two inputs. Each input has a required validator to ensure the user has entered a value.

<form [formGroup]="form" (ngSubmit)="submit()">
  <label for="first">First Name</label>
  <input formControlName="first" id="first" />

  <label for="last">Last Name</label>
  <input formControlName="last" id="last" />

  <button>submit</button>
</form>
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  form: FormGroup;

  constructor(private formBuilder: FormBuilder) {
    this.form = this.formBuilder.group({
      first: ['', Validators.required],
      last: ['', Validators.required],
    });
  }

  submit() {
    if (this.form.valid) {
      console.log(this.form);
    }
  }
}

Our form is using Angular Reactive Forms and the FormBuilder service to create the logic for our form. To add the logic to focus the first invalid input when the user submits, we will create an isolated directive. This directive we will call focusInvalidInput. When this directive is placed on our form it will listen for the submit event to know when to focus our first invalid input.

import { Directive, HostListener, ElementRef } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { FormGroup } from '@angular/forms';

@Directive({
  selector: '[focusInvalidInput]'
})
export class FormDirective {

  constructor(private el: ElementRef) { }

  @HostListener('submit')
  onFormSubmit() {
    const invalidControl = this.el.nativeElement.querySelector('.ng-invalid');

    if (invalidControl) {
      invalidControl.focus();  
    }
  }
}

To listen to the submit event on our form element, we can use the @HostListener decorator to call our method when fired. Once we have the event, we can check if there are any invalid inputs. The easiest way to check for invalid inputs is to check for the .ng-invalid CSS selectors that are created in the HTML by Angular.

To check the template of just our form, we can inject the ElementRef service which will provide a reference to our HTML form template. With the template we can use this.el.nativeElement.querySelector('.ng-invalid') to get a list of invalid inputs. If there are any invalid elements, we can then focus the first one in the list.

Once we have the directive created, we need to make sure we place it on the form element that we want the behavior.

<form focusInvalidInput [formGroup]="form" (ngSubmit)="submit()">
  <label for="first">First Name</label>
  <input formControlName="first" id="first" />

  <label for="last">Last Name</label>
  <input formControlName="last" id="last" />

  <button>submit</button>
</form>

If you want this behavior by default globally for all forms in your Angular application you can change the directive selector from [focusInvalidInput] to form Check out the full working demo below!

View Demo Code