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 { 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
#nameInputand#nameParagraphcreate 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:
- Angular creates the component instance.
- The template is rendered.
- Angular sees
#userInputand#messagein the template. @ViewChild('userInput')is matched to the<input>element.@ViewChild('message')is matched to the<p>element.- Once the view is fully initialized, Angular calls
ngAfterViewInit(). - Inside that method:
this.userInput.nativeElement.valuereturns"Aman"this.message.nativeElement.textContentreturns"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.
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,
stringis the normal primitive type. Stringrefers 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
#myInputin 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
| 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 | [(ngModel)]="myName" or reactive forms |
@ViewChild vs querying the DOM manually
| Technique | Angular-friendly | Scoped to component | Recommended |
|---|---|---|---|
@ViewChild | Yes | Yes | Yes |
document.querySelector() | No | No | Usually no |
document.querySelector() searches the whole document and ignores Angular's component boundaries. @ViewChild is the standard Angular approach.
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
#refNamein the template - Use
@ViewChild('refName')in the class - Access it after the view is initialized
- Prefer
string, notString - 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.
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
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Accessing Input Value from EventTarget in TypeScript
Learn why EventTarget has no value property in TypeScript and safely read values from HTML input events in Angular applications.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.