Question
How to Select an Element in an Angular Component Template
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 classElementRefto 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
#myInputis a label stuck on one object. @ViewChild('myInput')is how the component class says: bring me the object with that label.ElementRefis 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.
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 { , , , } ;
({
: ,
:
})
{
: = ;
() nameInput!: <>;
() nameParagraph!: <>;
() {
. = input;
}
() {
...();
.(...);
}
}
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:
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 = ..;
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:
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:
Comparisons
| Approach | What it does | Best for | Example |
|---|---|---|---|
| Template reference variable only | Refers to an element inside the template | Passing values in event bindings | (click)="save(myInput.value)" |
@ViewChild + ElementRef | Accesses a template element in the class | Focusing, measuring, scrolling, third-party libraries | @ViewChild('myInput') myInput!: ElementRef<HTMLInputElement>; |
| Property binding / interpolation | Updates the UI from component state | Most everyday Angular UI work | {{ myName }} |
| Angular forms | Manages form values and validation | Forms and user input | or reactive forms |
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
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?
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
@ViewChildto access both elements in the component class - Focus the input when the view finishes loading
- Update the displayed message as the user types
Keep learning
Related questions
Angular formGroup Error Explained: Fixing 'Can't bind to formGroup' in Reactive Forms
Learn why Angular shows 'Can't bind to formGroup' and how to fix it by importing ReactiveFormsModule correctly.
Fix "Element implicitly has an 'any' type" in TypeScript Object Indexing
Learn why TypeScript rejects string object indexing and how to fix it with keyof, unions, and typed object keys in React.
Fix "Property has no initializer" in Angular TypeScript Components
Learn why Angular TypeScript shows "Property has no initializer" and how to fix it using defaults, optional properties, or definite assignment.