Modern Angular applications rely heavily on data binding, services, and components. But sometimes, you must directly access HTML elements or child components. That is where Template Reference Variables, ViewChild, and safe DOM manipulation come into play.
This article explains:
What Template Reference Variables are
How to use ViewChild
When (and when not) to manipulate the DOM
Real examples used in actual Angular projects
What Are Template Reference Variables?
Template Reference Variables (TRVs) allow you to get a direct reference to an HTML element or Angular component from the template.
You create a variable with the # symbol.
Example:
<input #usernameInput type="text">
<button (click)="save(usernameInput.value)">Save</button>
Here:
TRVs with HTML Elements
Example: Accessing Input Value
<input #city type="text">
<button (click)="show(city.value)">Show</button>
Example: Access a DOM Element and Change Style
<p #para>Welcome to Angular</p>
<button (click)="highlight(para)">Highlight</button>
In the component:
highlight(el: HTMLElement) {
el.style.color = 'red';
}
TRVs with Child Components
You can also reference child components.
Parent Template:
<app-counter #counterRef></app-counter>
<button (click)="counterRef.increment()">Increment</button>
Child Component (Counter):
increment() { this.count++; }
This allows calling methods from the parent.
Using ViewChild for DOM Access in TypeScript
ViewChild is a decorator that helps you access:
From inside the TypeScript file.
Basic Syntax
@ViewChild('myInput') myInputElement!: ElementRef;
Template:
<input #myInput type="text">
Example: Accessing an Input Element
Template:
<input #emailInput type="text">
<button (click)="focusEmail()">Focus Input</button>
Component:
@ViewChild('emailInput') emailInput!: ElementRef;
focusEmail() {
this.emailInput.nativeElement.focus();
}
Example: Accessing a Child Component Using ViewChild
Child component:
export class TimerComponent {
start() { console.log('Timer started'); }
}
Parent template:
<app-timer></app-timer>
<button (click)="startTimer()">Start Timer</button>
Parent component:
@ViewChild(TimerComponent) timer!: TimerComponent;
startTimer() {
this.timer.start();
}
When Should You Use ViewChild?
Use ViewChild:
When you need to manipulate a specific DOM element
When you must call methods on a child component
When listening to custom component events is not enough
When you need to get initial sizes or layout values
When Should You Avoid ViewChild?
Avoid using ViewChild if:
You only need data binding (use ngModel, @Input, @Output)
You plan to rewrite everything using Angular animations
You want full control via RxJS and services
It causes too much coupling between components
Example: Auto-focus Input on Page Load
Template:
<input #username>
Component:
@ViewChild('username') username!: ElementRef;
ngAfterViewInit() {
this.username.nativeElement.focus();
}
Important:
Safety: Avoid Direct DOM Access When Possible
Angular runs in environments like:
Direct DOM access using nativeElement might break in some environments.
To handle this safely, Angular provides Renderer2.
DOM Manipulation Using Renderer2 (Recommended)
Renderer2 is the safe way to manipulate DOM elements.
Example:
constructor(private renderer: Renderer2) {}
@ViewChild('title') title!: ElementRef;
changeColor() {
this.renderer.setStyle(this.title.nativeElement, 'color', 'blue');
}
Template:
<h2 #title>Welcome</h2>
Renderer2 is platform-independent and recommended for long-term maintainability.
Case Study: Real-World Use of ViewChild
Scenario: You are building a data grid with a scrollable section. After filtering, you want to scroll back to the top.
Template:
<div class="table-container" #tableWrapper>
<!-- table rows --></div>
Component:
@ViewChild('tableWrapper') wrapper!: ElementRef;
scrollTop() {
this.wrapper.nativeElement.scrollTop = 0;
}
Call:
filterData() {
this.loadFilteredData();
this.scrollTop();
}
Useful in dashboards, reports, and admin panels.
Case Study: Call Method on a Child Component
Parent Template:
<app-product-list #productList></app-product-list>
<button (click)="refresh()">Refresh Products</button>
Child Component:
loadProducts() { /* API call */ }
Parent Component:
@ViewChild('productList') productList!: ProductListComponent;
refresh() {
this.productList.loadProducts();
}
This is useful for:
Reloading child tables
Resetting forms
Triggering calculations
Summary
| Concept | Purpose | Use Case |
|---|
| Template Reference Variable | Access element/component from template | Pass input value, call child functions |
| ViewChild | Access element/component from TypeScript | Focus input, call methods, control DOM |
| Renderer2 | Safe DOM manipulation | Styling, classes, attributes |
Conclusion
Angular provides safe and structured ways to access elements, components, and DOM properties.
Using Template Reference Variables and ViewChild correctly helps you:
Mastering these concepts is essential for building interactive, professional Angular applications.