DEV Community

Cover image for Angular 20 Control Flow Syntax: Goodbye *ngIf and *ngFor, Hello @if and @for
Parth Raval
Parth Raval

Posted on

Angular 20 Control Flow Syntax: Goodbye *ngIf and *ngFor, Hello @if and @for

Angular 20 has officially said goodbye to the classic structural directives like *ngIf, *ngFor, and *ngSwitch. These have been replaced with a modern control-flow syntax that looks and feels closer to JavaScript and TypeScript.

In this blog, we’ll explore the new Angular 20 HTML syntaxes, explain how they work, and show migration examples to help you adapt quickly.

Why the Change?

For years, Angular used structural directives (*ngIf, *ngFor, *ngSwitch) to control the DOM. While powerful, they had limitations:

  • Syntax was different from standard JS/TS.
  • Required * prefix and hidden ng-template wrapping.
  • Less readable for complex templates.

The new block-style control flow fixes this by making Angular templates feel more like writing plain code.

1. Conditional Rendering with @if

Old Way (Deprecated):

<div *ngIf="isLoggedIn; else guest">
  Welcome back, {{ userName }}!
</div>
<ng-template #guest>
  <p>Please log in</p>
</ng-template>
Enter fullscreen mode Exit fullscreen mode

New Way (Angular 20+):

@if (isLoggedIn) {
  <div>Welcome back, {{ userName }}!</div>
} @else {
  <p>Please log in</p>
}
Enter fullscreen mode Exit fullscreen mode
  • Cleaner syntax.
  • No need for extra .
  • Supports else if for multiple conditions.

2. Looping with @for

Old Way (Deprecated):

<ul>
  <li *ngFor="let item of items; index as i; trackBy: trackByFn">
    {{ i+1 }}. {{ item }}
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

New Way (Angular 20+):

<ul>
  @for (item of items; track trackByFn(item); let i = $index) {
    <li>{{ i+1 }}. {{ item }}</li>
  }
</ul>
Enter fullscreen mode Exit fullscreen mode
  • Uses block syntax, similar to for-of loops.
  • Built-in $index, $count, $first, $last.
  • track replaces trackBy with a more natural function call.

3. Switch Cases with @switch

Old Way (Deprecated):

<div [ngSwitch]="role">
  <p *ngSwitchCase="'admin'">Admin Access</p>
  <p *ngSwitchCase="'user'">User Access</p>
  <p *ngSwitchDefault>Guest Access</p>
</div>
Enter fullscreen mode Exit fullscreen mode

New Way (Angular 20+):

@switch (role) {
  @case ('admin') {
    <p>Admin Access</p>
  }
  @case ('user') {
    <p>User Access</p>
  }
  @default {
    <p>Guest Access</p>
  }
}
Enter fullscreen mode Exit fullscreen mode
  • Clear structure.
  • Looks like a real switch statement.
  • Easier to manage multiple cases.

4. Migration Made Easy

Angular provides a migration tool to automatically update your templates:

ng update @angular/core --name=control-flow-migration
Enter fullscreen mode Exit fullscreen mode

This will replace deprecated syntaxes (*ngIf, *ngFor, *ngSwitch) with their modern counter parts.

5. Example: Full Component in Angular 20

Here’s a simple component template using all new syntaxes:

<h1>User Dashboard</h1>

@if (isLoggedIn) {
  <p>Welcome, {{ userName }}</p>

  <ul>
    @for (task of tasks; let i = $index) {
      <li>{{ i+1 }}. {{ task }}</li>
    }
  </ul>

  @switch (role) {
    @case ('admin') {
      <button>Manage Users</button>
    }
    @case ('editor') {
      <button>Edit Content</button>
    }
    @default {
      <p>Basic User Access</p>
    }
  }
} @else {
  <p>Please log in to access your dashboard.</p>
}
Enter fullscreen mode Exit fullscreen mode

Key Benefits of the New Syntax

  • Cleaner & Readable → Closer to plain TypeScript.
  • No More * Prefix → No hidden ng-template wrappers.
  • Better Tooling → Stronger compiler diagnostics and editor support.
  • Future-Proof → Old syntax is deprecated, this is the new standard.

Top comments (0)