Skip to content
Angular ng templates 4 min read

Interpolation

Interpolation is the most direct way to get data from a component class onto the screen. You wrap a TypeScript expression in double curly braces — {{ expression }} — and Angular evaluates it against the component instance, converts the result to a string, and inserts it into the DOM. It is one-way binding from your data to the view, re-evaluated automatically whenever the underlying state changes. Because it is so common, getting comfortable with what is and isn’t allowed inside {{ }} pays off across every template you write.

Basic syntax

Place any property, signal, or expression of the component between the braces. Angular reads the value, calls toString() on it, and renders the text.

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

@Component({
  selector: 'app-profile',
  standalone: true,
  template: `
    <h1>Welcome, {{ name }}!</h1>
    <p>You have {{ unread() }} unread messages.</p>
    <p>Total with VAT: {{ price * 1.2 }}</p>
  `,
})
export class ProfileComponent {
  name = 'Ada';
  price = 100;
  unread = signal(3);
}

Output:

Welcome, Ada!
You have 3 unread messages.
Total with VAT: 120

Notice that unread is a signal, so it is invoked as unread(). Plain properties like name are read directly. In modern Angular, signals are the recommended way to hold reactive state, and they interpolate cleanly because calling them returns the current value.

The expression context

Interpolation expressions are evaluated against the component instance — the template context. You can reach any public member of the class directly by name; there is no this. prefix in templates. The expression engine deliberately restricts what you can do compared with full JavaScript, both for safety and to keep templates declarative.

Allowed inside {{ }}:

  • Property access, including nested paths: {{ user.address.city }}
  • Method calls: {{ formatDate(createdAt) }}
  • Arithmetic and string concatenation: {{ count + 1 }}, {{ first + ' ' + last }}
  • Ternary and the nullish/safe operators: {{ isAdmin ? 'Admin' : 'User' }}
  • Pipes for formatting: {{ today | date:'short' }}

Not allowed: assignments (=, +=), new, increment/decrement (++, --), bitwise operators, chained statements with ;, and references to global objects such as window, document, or console. Template expressions also cannot use typeof or instanceof.

Keep interpolation expressions simple and side-effect free. Angular may evaluate them many times per change-detection cycle, so they should be cheap and must never mutate state.

Safe navigation and nullish handling

When a value may be null or undefined, use the safe navigation operator ?. to short-circuit instead of throwing. Combine it with the nullish coalescing operator ?? to supply a fallback.

@Component({
  selector: 'app-account',
  standalone: true,
  template: `
    <p>City: {{ user?.address?.city ?? 'Unknown' }}</p>
  `,
})
export class AccountComponent {
  user: { address?: { city?: string } } | null = null;
}

Output:

City: Unknown

Without ?., reaching into a null user would surface an error during rendering. The safe operator makes optional data ergonomic and is essential when binding to objects loaded asynchronously.

Interpolation versus property binding

Interpolation is syntactic sugar over property binding for the special case where the target is a string. The two forms below are equivalent when the value is text:

GoalInterpolationProperty binding
Set text content<p>{{ title }}</p>
Set a string attribute<img src="{{ url }}"><img [src]="url">
Set a non-string valuenot suitable[disabled]="isBusy"

Use interpolation for visible text and string concatenation. Reach for property binding when the target expects a boolean, number, object, or any non-string value, since interpolation always coerces to a string — [disabled]="false" correctly disables nothing, whereas disabled="{{ false }}" produces the string "false", which is truthy as an attribute.

Formatting with pipes

Pipes transform a value for display without altering the underlying data. They chain naturally inside interpolation:

@Component({
  selector: 'app-receipt',
  standalone: true,
  imports: [],
  template: `
    <p>{{ amount | currency:'USD' }}</p>
    <p>{{ name | uppercase }}</p>
    <p>{{ createdAt | date:'mediumDate' }}</p>
  `,
})
export class ReceiptComponent {
  amount = 42.5;
  name = 'invoice';
  createdAt = new Date('2026-06-14');
}

Output:

$42.50
INVOICE
Jun 14, 2026

Customising the delimiters

In rare cases — typically when integrating with another templating system that also uses {{ }} — you can change the interpolation markers per component.

@Component({
  selector: 'app-custom',
  standalone: true,
  interpolation: ['[[', ']]'],
  template: `<p>Value: [[ value ]]</p>`,
})
export class CustomComponent {
  value = 'changed delimiters';
}

This is uncommon; prefer the default braces unless you have a concrete conflict to resolve.

Best Practices

  • Keep expressions short and readable; move anything non-trivial into a computed signal or a getter on the component.
  • Make expressions pure — no API calls, logging, or state mutation, because they run on every change-detection pass.
  • Prefer signals and computed() for derived values so the view stays in sync without manual wiring.
  • Use the safe navigation ?. and nullish coalescing ?? operators for data that can be absent.
  • Use pipes for display formatting (dates, currency, casing) rather than formatting strings by hand in the class.
  • Reach for property binding instead of interpolation whenever the target is not a string.
Last updated June 14, 2026
Was this helpful?