Angular Templates

By Syncfusion®, Inc. · Last updated

How a template connects HTML to the component class: interpolation, property, attribute, class and style binding, event and two-way binding, expressions and statements, reference variables, ng-container and ng-template.

What Are Angular Templates?

An Angular template is the HTML of a component, extended with Angular syntax that connects the HTML to the component's class.

The class holds the data and the methods. The template reads that data, displays it, and calls the methods when the user interacts with the page. When the data changes, Angular updates the HTML automatically.

Real-World Example

On an order-tracking page, the template displays the order number and status from the class, colors the status badge red or green, and disables the Cancel button once the order has shipped.

Clicking Cancel calls a method in the class. No code in the class touches the DOM directly.

Classdata and methodsTemplateHTML on screen{{ value }} interpolation[property] property binding(event) event binding[(ngModel)] two-way binding

Square brackets send data into the page. Round brackets send events back to the class.

Template Syntax Overview

Angular adds a small set of symbols to HTML. Each symbol tells Angular which way the data moves.

SyntaxNameData directionExample
{{ }}InterpolationClass → template (text){{ userName }}
[ ]Property bindingClass → template (element property)[disabled]="isSaving"
[attr.x]Attribute bindingClass → template (HTML attribute)[attr.aria-label]="label"
[class.x]Class bindingClass → template (CSS class)[class.active]="isActive"
[style.x]Style bindingClass → template (inline style)[style.width.px]="size"
( )Event bindingTemplate → class(click)="save()"
[( )]Two-way bindingBoth directions[(ngModel)]="email"
#nameTemplate reference variableInside the template#searchBox

A simple way to remember the brackets:

  • Square brackets [ ] send a value into the element.
  • Round brackets ( ) send an event out to the class.
  • Both [( )] do both. This shape is often called "banana in a box".

Interpolation

Interpolation inserts a value from the class into the text of the page. You write the value inside double curly braces: {{ value }}.

Angular evaluates the expression between the braces, converts the result to text and places it in the HTML. When the value changes, the text updates.

Interpolation inserts class values into text

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

@Component({
  selector: 'app-root',
  template: `
    <h3>Order #{{ orderId }}</h3>
    <p>Customer: {{ customer }}</p>
    <p>Items: {{ items }} · Total: ₹{{ items * price }}</p>
  `,
})
export class App {
  orderId = 10482;
  customer = 'Asha Kumar';
  items = 3;
  price = 450;
}

Interpolation works only in text and in attribute values written as text. To set a property such as disabled, use property binding.

Interpolation always inserts plain text. If a value contains HTML, such as <b>Sale</b>, Angular displays the tags as text instead of running them. This protects your app from code injected through user data.

Property Binding

Property binding sets a property of an HTML element, or an input of a component, from a value in the class. You write the property name in square brackets: [property]="expression".

The value on the right is an expression, not plain text. [disabled]="isSaving" reads the isSaving property from the class and passes its true or false value to the button.

Property binding controls the disabled state and the image

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

@Component({
  selector: 'app-root',
  template: `
    <img [src]="avatarUrl" [alt]="userName" width="48" height="48" />
    <p>{{ userName }}</p>
    <button [disabled]="isSaving">Save profile</button>
    <p>Saving: {{ isSaving }}</p>
  `,
})
export class App {
  userName = 'Ravi';
  avatarUrl = 'data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 48 48%22%3E%3Ccircle cx=%2224%22 cy=%2224%22 r=%2224%22 fill=%22%232563eb%22/%3E%3C/svg%3E';
  isSaving = true;
}

Change isSaving to false and run the code again. The button becomes clickable.

PointInterpolation {{ }}Property binding [ ]
Where it writesText contentAn element or component property
Value typeAlways converted to textKeeps its type: boolean, number, object
Example<p>{{ name }}</p><button [disabled]="busy">
Use it forDisplaying valuesdisabled, src, value, hidden, component inputs

Attribute Binding

Most HTML attributes have a matching DOM property, so property binding works for them. Some attributes have no matching property, for example aria-label, colspan and data-* attributes.

For these, use attribute binding: [attr.name]="expression". Angular calls setAttribute on the element. If the value is null, Angular removes the attribute.

Attribute binding sets ARIA and data attributes

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

@Component({
  selector: 'app-root',
  template: `
    <button [attr.aria-label]="'Delete ' + fileName" [attr.data-file-id]="fileId">🗑️</button>
    <table border="1" cellpadding="6">
      <tr><td [attr.colspan]="columns">Quarterly report</td></tr>
      <tr><td>Q1</td><td>Q2</td><td>Q3</td></tr>
    </table>
  `,
})
export class App {
  fileName = 'invoice-2026.pdf';
  fileId = 77;
  columns = 3;
}

The heading cell spans all three columns because colspan is set from the columns property.

Class Binding

Class binding adds or removes CSS classes based on values in the class.

  • [class.name]="condition" adds one class when the condition is true and removes it when it is false.
  • [class]="expression" sets several classes at once from a string, an array or an object.

Class binding colors each status badge

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

@Component({
  selector: 'app-root',
  template: `
    <p>Order 1: <span class="badge" [class.ok]="paid" [class.warn]="!paid">{{ paid ? 'Paid' : 'Pending' }}</span></p>
    <p>Order 2: <span class="badge" [class]="{ badge: true, ok: false, warn: true }">Pending</span></p>
  `,
  styles: `
    .badge { padding: 2px 10px; border-radius: 10px; font-size: 13px; }
    .ok { background: #dcfce7; color: #166534; }
    .warn { background: #fef3c7; color: #92400e; }
  `,
})
export class App {
  paid = true;
}

Style Binding

Style binding sets a single inline CSS property from a value in the class: [style.property]="expression".

You can add a unit to the binding name. [style.width.px]="progress" turns the number 60 into 60px.

Style binding draws a progress bar

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

@Component({
  selector: 'app-root',
  template: `
    <p>Upload: {{ progress }}%</p>
    <div class="track">
      <div class="bar" [style.width.%]="progress" [style.background-color]="progress < 100 ? '#2563eb' : '#16a34a'"></div>
    </div>
  `,
  styles: `
    .track { width: 240px; height: 10px; background: #e5e7eb; border-radius: 5px; overflow: hidden; }
    .bar { height: 100%; }
  `,
})
export class App {
  progress = 65;
}

Change progress to 100 and run it again. The bar fills up and turns green.

PointClass bindingStyle binding
What it changesThe element's CSS classesOne inline style property
Where the design livesIn the stylesheetIn the binding itself
Best forNamed states: active, error, selectedValues calculated at run time: widths, positions, colors

Prefer class binding for visual states. The colors and spacing stay in the stylesheet, where they are easier to change. Use style binding when the value is calculated, such as a percentage.

Event Binding

Event binding runs a method in the class when an event happens on an element. You write the event name in round brackets: (event)="statement".

Common events are click, input, change, submit, keyup and blur. Angular also supports key filters, such as (keyup.enter), which fires only when the Enter key is pressed.

To read details of the event, pass $event. It is the browser's native event object.

Event binding calls class methods

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

@Component({
  selector: 'app-root',
  template: `
    <p>Items in cart: {{ count }}</p>
    <button (click)="add()">Add to cart</button>
    <button (click)="clear()">Clear</button>
    <p><input placeholder="Type and press Enter" (keyup.enter)="onSearch($event)" /></p>
    <p>Last search: {{ lastSearch }}</p>
  `,
})
export class App {
  count = 0;
  lastSearch = '(none)';

  add() {
    this.count = this.count + 1;
  }

  clear() {
    this.count = 0;
  }

  onSearch(event: Event) {
    this.lastSearch = (event.target as HTMLInputElement).value;
  }
}

Click the buttons, then type a word in the box and press Enter.

Two-Way Data Binding

Two-way data binding keeps a form field and a class property in sync. When the user types, the property updates. When the property changes in code, the field updates.

The syntax combines both brackets: [(ngModel)]="property". ngModel comes from Angular's forms package, so the component must import FormsModule.

<input>what the user typesdisplayNameclass property(ngModelChange): typing updates the property[ngModel]: the property updates the field

[(ngModel)] keeps the field and the property in sync in both directions.

Two-way binding keeps the input and the class in sync

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

@Component({
  selector: 'app-root',
  imports: [FormsModule],
  template: `
    <label>Display name: <input [(ngModel)]="displayName" /></label>
    <p>Preview: <strong>{{ displayName }}</strong> ({{ displayName.length }} characters)</p>
    <button (click)="displayName = 'Guest'">Reset</button>
  `,
})
export class App {
  displayName = 'Asha';
}

Type in the box. The preview updates on every key press. Click Reset. The class changes the value, and the input follows.

[(ngModel)]="displayName" is a short form of two bindings:

<input [ngModel]="displayName" (ngModelChange)="displayName = $event" />

If you forget imports: [FormsModule], Angular reports NG0303: Can't bind to 'ngModel' since it isn't a known property of 'input'.

Template Expressions

A template expression is the JavaScript-like code inside {{ }} or on the right side of a property binding. Angular runs it to produce a value.

Expressions can read class properties, call methods, do arithmetic, compare values and use the conditional operator ? :.

Expressions calculate values for the template

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

@Component({
  selector: 'app-root',
  template: `
    <p>Subtotal: ₹{{ price * quantity }}</p>
    <p>Shipping: {{ price * quantity >= 999 ? 'Free' : '₹49' }}</p>
    <p>Discount code: {{ code.toUpperCase() }}</p>
    <p>Total items: {{ cartSize() }}</p>
  `,
})
export class App {
  price = 349;
  quantity = 3;
  code = 'save10';
  cart = ['Keyboard', 'Mouse', 'Cable'];

  cartSize() {
    return this.cart.length;
  }
}

Expressions have rules:

  • No assignments. {{ total = 5 }} is not allowed.
  • No new, ++ or --.
  • Keep them fast. Angular may run an expression many times, so avoid heavy work inside it.
  • No side effects. An expression should only read data, never change it.

Template Statements

A template statement is the code on the right side of an event binding. Angular runs it when the event fires.

Unlike expressions, statements are allowed to change data. They usually call a method or assign a value.

PointTemplate expressionTemplate statement
Where it appears{{ }} and [property]="..."(event)="..."
When it runsEvery time Angular checks the viewOnly when the event fires
Can change dataNoYes
Typical exampleprice * quantitysave() or count = 0

Statements change data when an event fires

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

@Component({
  selector: 'app-root',
  template: `
    <p>Notifications: {{ unread }}</p>
    <button (click)="unread = unread + 1">Simulate new message</button>
    <button (click)="markAllRead(); lastAction = 'Marked as read'">Mark all read</button>
    <p>{{ lastAction }}</p>
  `,
})
export class App {
  unread = 2;
  lastAction = '';

  markAllRead() {
    this.unread = 0;
  }
}

A statement can run several actions separated by a semicolon, as the second button shows. For anything longer, move the code into a method.

Template Reference Variables

A template reference variable gives a name to an element inside the template, so other parts of the same template can use it. You declare it with #name on the element.

The variable refers to the DOM element itself. For example, #query on an <input> lets a button read query.value.

A reference variable reads an input without a class property

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

@Component({
  selector: 'app-root',
  template: `
    <input #tag placeholder="New tag" />
    <button (click)="addTag(tag.value); tag.value = ''">Add tag</button>
    <p>Tags: {{ tags.join(', ') }}</p>
  `,
})
export class App {
  tags = ['angular', 'frontend'];

  addTag(value: string) {
    if (value.trim()) {
      this.tags.push(value.trim());
    }
  }
}

Type a tag and click Add tag. The button reads the input through tag.value and then clears it.

A reference variable is visible only inside the template where it is declared. The class cannot read it directly.

ng-container

<ng-container> is a grouping element that Angular does not render in the final HTML. Only its content appears on the page.

Use it when you need to group elements for a control-flow block or a directive, but an extra <div> would break your layout or your HTML structure. For example, a <tr> may contain only cells, so a wrapper <div> inside it is invalid HTML.

ng-container groups cells without adding an element

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

@Component({
  selector: 'app-root',
  template: `
    <table border="1" cellpadding="6">
      <tr>
        <th>Plan</th>
        <ng-container>
          <th>Price</th>
          <th>Users</th>
        </ng-container>
      </tr>
      <tr>
        <td>Team</td>
        @if (showDetails) {
          <ng-container>
            <td>₹999</td>
            <td>10</td>
          </ng-container>
        }
      </tr>
    </table>
  `,
})
export class App {
  showDetails = true;
}

Open the browser's developer tools on a real project and you will see no ng-container element in the page. Only the <th> and <td> cells remain.

ng-template

<ng-template> defines a block of HTML that Angular does not render by itself. The block stays hidden until your code tells Angular where and when to render it.

You give the template a reference variable, such as #loading, and render it with NgTemplateOutlet or use it in a control-flow block. This lets you define one piece of HTML and display it in several places.

ng-template defines reusable HTML that renders only on request

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

@Component({
  selector: 'app-root',
  imports: [NgTemplateOutlet],
  template: `
    <ng-template #emptyState>
      <p class="empty">📭 Nothing here yet.</p>
    </ng-template>

    <h4>Inbox</h4>
    <ng-container *ngTemplateOutlet="emptyState" />

    <h4>Archive</h4>
    <ng-container *ngTemplateOutlet="emptyState" />
  `,
  styles: `.empty { color: #6b7280; margin: 4px 0 12px; }`,
})
export class App {}

The empty-state message is written once and rendered twice.

Pointng-containerng-template
Rendered automaticallyYes, its content appears in placeNo, only when you render it
Adds an element to the pageNoNo
Main useGroup elements without a wrapperDefine HTML to render later or in several places

Common Mistakes

MistakeWhat you seeFix
Interpolation inside a property binding[src]="{{ url }}" causes a template parse errorUse one form: [src]="url"
Quotes missing around a text value[label]="Save" looks for a property named SaveWrap text in inner quotes: [label]="'Save'"
Property binding for an ARIA attributeCan't bind to 'aria-label'Use attribute binding: [attr.aria-label]
[(ngModel)] without FormsModuleNG0303: Can't bind to 'ngModel'Add FormsModule to the component's imports
Changing data inside {{ }}A template parse error about assignmentsChange data in an event statement or a method
Calling a slow method in an expressionThe page becomes slowStore the result in a property instead
Expecting ng-template to appearIts content never showsRender it with *ngTemplateOutlet or a control-flow block

Check Yourself

Exercises

What to Remember

  • A template is HTML plus Angular syntax that connects it to the component class.
  • {{ }} and [ ] send data from the class to the page. ( ) sends events from the page to the class. [( )] does both.
  • ng-container groups content without adding an element. ng-template defines HTML that renders only when you ask for it.

Next: Styling Components, how to add CSS to components and control where it applies.