Question

How to Select an Element in an Angular Component Template

typescriptangularangular-components

Question

In Angular, how can you access an element that is defined inside a component template?

For example, consider this component:

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

@Component({
  selector: 'display',
  template: `
    <input #myname (input)="updateName(myname.value)" />
    <p>My name : {{ myName }}</p>
  `
})
export class DisplayComponent {
  myName: string = 'Aman';

  updateName(input: string) {
    this.myName = input;
  }
}

How can you get a reference to the <input> or <p> element from within the component class?

Short Answer

By the end of this page, you will understand how Angular lets you reference DOM elements inside a component template. You will learn when to use template reference variables, when to use @ViewChild, how ElementRef works, and why Angular usually prefers data binding over direct DOM access.

Concept

In Angular, elements inside a component template belong to that component's view. If you want to access one of those elements from the component class, the most common approach is to use template reference variables together with @ViewChild.

Angular does not encourage frequent direct DOM manipulation the way some other libraries do. Instead, Angular is designed around:

  • property binding for sending data into the template
  • event binding for reacting to user actions
  • interpolation for displaying values
  • directives for changing behavior declaratively

However, sometimes you do need the actual element, such as when:

  • focusing an input
  • reading its size or position
  • integrating with a third-party library
  • controlling scroll behavior

To do that, Angular provides:

  • template reference variables like #myInput
  • @ViewChild() to access that reference in the class
  • ElementRef to wrap the native DOM element

This matters because it helps you write Angular code that stays structured and testable while still letting you access the DOM when necessary.

Mental Model

Think of the component template as a room full of labeled objects.

  • A template reference variable like #myInput is a label stuck on one object.
  • @ViewChild('myInput') is how the component class says: bring me the object with that label.
  • ElementRef is the container holding the actual DOM object.

So instead of searching the whole document manually, Angular lets you label the element in the template and request it directly from the component.

Take Quiz

Syntax and Examples

The basic pattern looks like this:

import { Component, ElementRef, ViewChild } from '@angular/core';

@Component({
  selector: 'app-example',
  template: `
    <input #myInput />
    <p #myParagraph>Hello</p>
  `
})
export class ExampleComponent {
  @ViewChild('myInput') myInput!: ElementRef<HTMLInputElement>;
  @ViewChild('myParagraph') myParagraph!: ElementRef<HTMLParagraphElement>;
}

You create references in the template:

<input #myInput />
<p #myParagraph>Hello</p>

Then you read them in the class using @ViewChild().

Example: focus an input

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

@Component({
  selector: 'app-display',
  template: `
    <input #nameInput (input)="updateName(nameInput.value)" />
    <p #nameParagraph>My name : {{ myName }}</p>
  `
})
export class DisplayComponent implements AfterViewInit {
  myName: string = 'Aman';

  @ViewChild('nameInput') nameInput!: ElementRef<HTMLInputElement>;
  @ViewChild('nameParagraph') nameParagraph!: ElementRef<HTMLParagraphElement>;

  updateName(input: string) {
    this.myName = input;
  }

  ngAfterViewInit() {
    this.nameInput.nativeElement.focus();
    console.log(this.nameParagraph.nativeElement.textContent);
  }
}

What this example does

  • #nameInput and #nameParagraph create references in the template.
  • @ViewChild('nameInput') and @ViewChild('nameParagraph') make them available in the class.
  • ngAfterViewInit() is used because the view must exist before Angular can provide those element references.

Accessing a value without @ViewChild

If you only need the element inside the template event itself, a template reference variable is enough:

<input #myInput (click)="logValue(myInput.value)" />
logValue(value: string) {
  console.log(value);
}

In this case, you are not accessing the DOM element from the class directly. You are just passing its value through the template.

Step by Step Execution

Consider this example:

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

@Component({
  selector: 'app-demo',
  template: `
    <input #userInput value="Aman" />
    <p #message>Welcome</p>
  `
})
export class DemoComponent implements AfterViewInit {
  @ViewChild('userInput') userInput!: ElementRef<HTMLInputElement>;
  @ViewChild('message') message!: ElementRef<HTMLParagraphElement>;

  ngAfterViewInit() {
    console.log(this.userInput.nativeElement.value);
    console.log(this.message.nativeElement.textContent);
  }
}

Here is what happens step by step:

  1. Angular creates the component instance.
  2. The template is rendered.
  3. Angular sees #userInput and #message in the template.
  4. @ViewChild('userInput') is matched to the <input> element.
  5. @ViewChild('message') is matched to the <p> element.
  6. Once the view is fully initialized, Angular calls ngAfterViewInit().
  7. Inside that method:
    • this.userInput.nativeElement.value returns "Aman"
    • this.message.nativeElement.textContent returns "Welcome"

The key idea is that the reference is only reliably available after the view has been initialized.

Real World Use Cases

Direct access to template elements is useful in situations like these:

Focusing form fields

this.emailInput.nativeElement.focus();

Useful for:

  • login forms
  • search bars
  • validation errors

Reading element size

const width = this.panel.nativeElement.offsetWidth;

Useful for:

  • responsive UI adjustments
  • charts and canvas sizing
  • layout calculations

Scrolling to a section

this.section.nativeElement.scrollIntoView();

Useful for:

  • error summaries
  • anchor navigation
  • chat windows

Connecting third-party libraries

Some libraries require a real DOM node:

const el = this.chartContainer.nativeElement;

Useful for:

  • charts
  • maps
  • animation libraries

Reading raw input values

Although Angular forms are usually better for this, raw access is sometimes used in small components or utility widgets.

Take Quiz

Real Codebase Usage

In real Angular projects, developers usually avoid direct DOM access unless there is a clear reason. Common patterns include:

1. Prefer binding first

Instead of reading text from a <p> element, store the value in a component property:

myName = 'Aman';

Then display it in the template:

<p>{{ myName }}</p>

This is cleaner than reading textContent from the DOM.

2. Use @ViewChild for imperative actions

Good examples:

  • focus an input
  • open or close a native dialog
  • measure an element
  • attach a library to a container

3. Use lifecycle hooks correctly

A common real-world pattern:

ngAfterViewInit() {
  this.searchInput.nativeElement.focus();
}

4. Use guard clauses

When an element may not exist, developers often check before using it:

if (!this.modalBody) return;
this.modalBody.nativeElement.scrollTop = 0;

5. Prefer Angular abstractions when possible

For styling, showing, hiding, or reacting to changes, developers usually choose:

  • [class.someClass]
  • [style.width.px]
  • *ngIf
  • *ngFor
  • forms APIs
  • custom directives

These are usually better than manually changing the DOM.

Common Mistakes

1. Accessing @ViewChild too early

Broken example:

export class DemoComponent {
  @ViewChild('myInput') myInput!: ElementRef<HTMLInputElement>;

  constructor() {
    console.log(this.myInput.nativeElement); // Too early
  }
}

Why it fails:

  • The view has not been created yet.

Fix:

  • Use ngAfterViewInit().
ngAfterViewInit() {
  console.log(this.myInput.nativeElement);
}

2. Using String instead of string

Broken example:

updateName(input: String) {
  this.myName = input;
}

Why to avoid it:

  • In TypeScript, string is the normal primitive type.
  • String refers to the wrapper object type.

Fix:

updateName(input: string) {
  this.myName = input;
}

3. Manipulating the DOM when binding is enough

Unnecessary approach:

this.nameParagraph.nativeElement.textContent = 'New text';

Better Angular approach:

this.myName = 'New text';

Then let the template update automatically.

4. Forgetting the template reference variable

Broken example:

@ViewChild('myInput') myInput!: ElementRef<HTMLInputElement>;

But template:

<input />

Why it fails:

  • There is no #myInput in the template.

Fix:

<input #myInput />

5. Overusing nativeElement

Direct DOM manipulation can make components harder to test and less aligned with Angular's design. Use it only when needed.

Comparisons

ApproachWhat it doesBest forExample
Template reference variable onlyRefers to an element inside the templatePassing values in event bindings(click)="save(myInput.value)"
@ViewChild + ElementRefAccesses a template element in the classFocusing, measuring, scrolling, third-party libraries@ViewChild('myInput') myInput!: ElementRef<HTMLInputElement>;
Property binding / interpolationUpdates the UI from component stateMost everyday Angular UI work{{ myName }}
Angular formsManages form values and validationForms and user input[(ngModel)]="myName" or reactive forms

@ViewChild vs querying the DOM manually

TechniqueAngular-friendlyScoped to componentRecommended
@ViewChildYesYesYes
document.querySelector()NoNoUsually no

document.querySelector() searches the whole document and ignores Angular's component boundaries. @ViewChild is the standard Angular approach.

Take Quiz

Cheat Sheet

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

Template

<input #myInput />
<p #myParagraph>Hello</p>

Component

@ViewChild('myInput') myInput!: ElementRef<HTMLInputElement>;
@ViewChild('myParagraph') myParagraph!: ElementRef<HTMLParagraphElement>;

Safe access point

ngAfterViewInit() {
  console.log(this.myInput.nativeElement.value);
}

Use when

  • focusing an element
  • measuring size
  • scrolling
  • integrating a third-party DOM library

Prefer binding instead when

  • showing text
  • updating UI state
  • toggling visibility
  • setting classes or styles

Remember

  • Add #refName in the template
  • Use @ViewChild('refName') in the class
  • Access it after the view is initialized
  • Prefer string, not String
  • Avoid direct DOM manipulation unless necessary

FAQ

How do I get an input element in Angular component code?

Use a template reference variable like #myInput and read it with @ViewChild('myInput') in the component class.

Can I access a <p> element with @ViewChild in Angular?

Yes. Add a reference such as #message to the <p> element and query it with @ViewChild('message').

Why is my @ViewChild undefined in Angular?

Usually because you are trying to use it before the view has been initialized. Access it in ngAfterViewInit().

Should I use document.querySelector() in Angular?

Usually no. @ViewChild is the preferred Angular way because it works with component templates directly.

Do I always need ElementRef to access template elements?

If you want the actual DOM element, yes, ElementRef is common. But for many tasks, Angular bindings are a better choice than DOM access.

Is direct DOM manipulation good practice in Angular?

Only when needed. For most UI updates, use Angular bindings instead of changing nativeElement manually.

Take Quiz

Mini Project

Description

Build a small Angular component that lets a user type a message, focuses the input automatically when the component loads, and scrolls to the result text when the message changes. This demonstrates template reference variables, @ViewChild, ElementRef, and the correct lifecycle hook.

Goal

Create a component that accesses template elements from the class to focus an input and interact with a paragraph element.

Requirements

  • Add an input element with a template reference variable
  • Add a paragraph element with a template reference variable
  • Use @ViewChild to access both elements in the component class
  • Focus the input when the view finishes loading
  • Update the displayed message as the user types
Take Quiz

Keep learning

Related questions

View more