Reader Stacks

How to Set Focus on an Input Programmatically in Angular

@ViewChild plus ElementRef is the standard Angular way to reach into the DOM and focus a specific input — necessary because Angular doesn't expose a native, template-only way to do this.

How to Set Focus on an Input Programmatically in Angular

Focusing a specific input programmatically — after a modal opens, on component load, after a validation error — needs Angular's @ViewChild decorator combined with ElementRef, since there's no purely template-based way to trigger this kind of direct DOM interaction.

Basic setup with @ViewChild

@Component({
    template: ``
})
export class LoginComponent implements AfterViewInit {
    @ViewChild('emailInput') emailInput!: ElementRef;

    ngAfterViewInit(): void {
        this.emailInput.nativeElement.focus();
    }
}

The template reference variable (#emailInput) links the template element to the @ViewChild property in the component class — nativeElement is then the actual underlying DOM element, giving access to real DOM methods like .focus().

Why ngAfterViewInit, not ngOnInit

ngOnInit() runs before Angular has finished initializing the view and its child elements — @ViewChild references aren't guaranteed to be populated yet at that point, which is exactly why focusing an element needs to happen in ngAfterViewInit() instead, once the view is fully rendered and the reference is genuinely available.

Focusing an input in response to a user action

@Component({
    template: `
        
        
    `
})
export class HeaderComponent {
    @ViewChild('searchInput') searchInput?: ElementRef;
    showSearch = false;

    openSearch(): void {
        this.showSearch = true;
        setTimeout(() => this.searchInput?.nativeElement.focus());
    }
}

The setTimeout here (with no delay argument, just deferring to the next event loop tick) matters because *ngIf only creates the input element after showSearch becomes true and Angular's next change detection cycle runs — attempting to focus it in the same synchronous call that sets showSearch = true would fail, since the element doesn't exist in the DOM yet at that exact moment.

Focusing the first invalid field after a failed form validation

@ViewChildren('formField') formFields!: QueryList;

onSubmit(): void {
    if (this.form.invalid) {
        const firstInvalidControl = Object.keys(this.form.controls).find(
            key => this.form.get(key)?.invalid
        );

        const fieldIndex = Object.keys(this.form.controls).indexOf(firstInvalidControl!);
        this.formFields.toArray()[fieldIndex]?.nativeElement.focus();
    }
}

@ViewChildren (plural) is the equivalent of @ViewChild for a collection of matching elements — useful here for finding and focusing whichever specific field in a longer form actually failed validation, rather than only being able to reference one single named element.

Creating a reusable auto-focus directive, for repeated use across the app

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

    ngAfterViewInit(): void {
        this.el.nativeElement.focus();
    }
}

Extracting this into a small reusable directive, following the custom directive pattern covered elsewhere on this site, avoids repeating the @ViewChild/ngAfterViewInit boilerplate in every component that needs to autofocus an input on load.