Angular  

Understanding Template Reference Variables, ViewChild, and DOM Manipulation in Angular

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:

  • #usernameInput refers to the <input> element

  • You can pass its value directly into a method

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:

  • HTML elements

  • Angular components

  • Directives

  • Template reference variables

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:

  • Always use ngAfterViewInit()

  • The DOM will be available only after view initialization

Safety: Avoid Direct DOM Access When Possible

Angular runs in environments like:

  • Browser

  • Server (Angular Universal)

  • Web workers

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

ConceptPurposeUse Case
Template Reference VariableAccess element/component from templatePass input value, call child functions
ViewChildAccess element/component from TypeScriptFocus input, call methods, control DOM
Renderer2Safe DOM manipulationStyling, 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:

  • Control DOM when needed

  • Reduce complex event passing

  • Access child components

  • Create smooth user experiences

Mastering these concepts is essential for building interactive, professional Angular applications.