15 Jan 2026
8 min

Angular 21.1: Key Features and Improvements

Angular 21.1 brings several exciting features that enhance both developer experience and application capabilities. Let’s dive into the most significant changes that landed in this release.

Template Compilation Enhancements

Multiple Switch Case Matching

One of the most practical additions is support for multiple case matching in switch statements. Previously, if you needed to handle multiple cases with the same logic, you had to repeat the template code or use workarounds.

Before (Angular 21.0):

@switch (status) {
  @case ('pending') {
    <app-loading />
  }
  @case ('processing') {
    <app-loading />
  }
  @case ('completed') {
    <app-success />
  }
}

Now (Angular 21.1):

@switch (status) {
  @case ('pending')
  @case ('processing') {
    <app-loading />
  }
  @case ('completed') {
    <app-success />
  }
}

The compiler now supports empty cases that fall through to the next case, making templates cleaner and reducing duplication. This brings Angular’s template syntax closer to JavaScript’s native switch behavior.

Support for Spread Operators

Angular 21.1 introduces comprehensive support for spread operators in templates, making it easier to work with arrays and objects directly in your template expressions.

Rest Arguments in Function Calls:

@Component({
  template: `
    <button (click)="logValues(...items)">Log All</button>
  `
})
export class MyComponent {
  items = [1, 2, 3, 4, 5];
  
  logValues(...values: number[]) {
    console.log(values);
  }
}

Spread Elements in Array Literals:

@Component({
  template: `
    <app-list [items]="[...baseItems, ...additionalItems]" />
  `
})
export class MyComponent {
  baseItems = [1, 2, 3];
  additionalItems = [4, 5, 6];
}

Spread Expressions in Object Literals:

@Component({
  template: `
    <app-user [data]="{...defaultUser, ...customFields}" />
  `
})
export class MyComponent {
  defaultUser = { name: '', email: '' };
  customFields = { age: 25, role: 'admin' };
}

These features eliminate the need for helper methods when composing data structures in templates, leading to more concise and readable code.

Signal Forms: The [formField] Directive

Signal Forms, introduced experimentally in Angular 21.0, receive an important update. The `[field]` directive has been renamed to `[formField]` for better clarity and consistency.

Migration:

// Before (Angular 21.0)
<input type="email" [field]="loginForm.email" />

// After (Angular 21.1)
<input type="email" [formField]="loginForm.email" />

This is purely a naming change – the functionality remains identical. The directive still provides automatic two-way binding between form fields and Signal Forms, handles validation state synchronization, and works with both native inputs and custom controls.

Complete Example:

import { Component, signal } from '@angular/core';
import { form, FormField, required, email } from '@angular/forms/signals';

interface LoginData {
  email: string;
  password: string;
}

@Component({
  selector: 'app-login',
  imports: [FormField],
  template: `
    <form (submit)="onSubmit($event)">
      <label>
        Email:
        <input type="email" [formField]="loginForm.email" />
      </label>
      @if (loginForm.email().touched() && loginForm.email().invalid()) {
        <div class="error">
          @for (error of loginForm.email().errors(); track error) {
            <p>{{ error.message }}</p>
          }
        </div>
      }
      
      <label>
        Password:
        <input type="password" [formField]="loginForm.password" />
      </label>
      
      <button type="submit" [disabled]="loginForm().invalid()">
        Log In
      </button>
    </form>
  `
})
export class LoginComponent {
  loginModel = signal<LoginData>({
    email: '',
    password: ''
  });

  loginForm = form(this.loginModel, (f) => {
    required(f.email, { message: 'Email is required' });
    email(f.email, { message: 'Please enter a valid email' });
    required(f.password, { message: 'Password is required' });
  });

  onSubmit(event: Event) {
    event.preventDefault();
    if (this.loginForm().valid()) {
      console.log('Form submitted:', this.loginModel());
    }
  }
}

Additional Signal Forms Improvements

Angular 21.1 also brings several fixes and enhancements to Signal Forms:

Custom controls support: Better support for custom controls with non-signal-based models

Input requirements: Custom controls can now require `dirty`, `hidden`, and `pending` inputs

Readonly arrays: Full support for readonly arrays in signal forms

Async validation: Proper cleanup of abort listeners after validation timeout

[Start the new year with knowledge about revolutionary Signal Forms, Scalable Architecture, and Modern Reactivity. Workshop date: 02-03.03.2026]

Router Enhancements

Angular 21.1 publishes the Router’s integration with the platform Navigation API as an experimental feature. The Navigation API is a modern browser standard that provides better control over browser navigation compared to the older History API.

The Navigation API offers several advantages:

– Better handling of navigation state

– Improved access to navigation history

– More reliable event handling

– Enhanced support for single-page applications

This integration allows Angular Router to leverage these capabilities while maintaining backward compatibility with existing applications.

Key Points:

– This feature is experimental and may change in future versions

– Provides foundation for future router improvements

– No action required for most applications

– Browser support is gradually improving

Route Injector Cleanup (Experimental)

Angular 21.1 introduces experimental automatic cleanup of `EnvironmentInjector`s associated with routes that are no longer active or stored. This helps manage memory by releasing resources held by unused injectors.

The Problem:

By default, Angular doesn’t destroy injectors of detached routes, even when they’re no longer stored by `RouteReuseStrategy`. This usually isn’t an issue for most applications, but can lead to memory concerns in apps with complex route hierarchies or long-lived sessions.

The Solution:

Enable automatic cleanup with the `withExperimentalAutoCleanupInjectors()` feature:

import { 
  provideRouter, 
  withExperimentalAutoCleanupInjectors 
} from '@angular/router';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(
      routes, 
      withExperimentalAutoCleanupInjectors()
    )
  ]
};

When enabled, the router automatically:

– Checks which routes are currently stored by the `RouteReuseStrategy` after each navigation

– Destroys injectors of any detached routes not currently stored

– Manages cleanup without manual intervention (when using `BaseRouteReuseStrategy`)

Custom RouteReuseStrategy Considerations:

If you have a custom `RouteReuseStrategy` that doesn’t extend `BaseRouteReuseStrategy`, implement `shouldDestroyInjector()`:

@Injectable()
export class CustomRouteReuseStrategy implements RouteReuseStrategy {
  private readonly handles = new Map<Route, DetachedRouteHandle>();

  shouldDestroyInjector(route: Route): boolean {
    // Return true to destroy the injector, false to keep it
    return !route.data?.['retainInjector'];
  }

  // If your strategy stores handles, provide this method
  retrieveStoredRouteHandles(): DetachedRouteHandle[] {
    return Array.from(this.handles.values());
  }

  // ... other RouteReuseStrategy methods
}

Manual Cleanup:

For manual control, use the `destroyDetachedRouteHandle()` function:

import { destroyDetachedRouteHandle } from '@angular/router';

// Inside your custom strategy
if (this.handles.size > MAX_CACHE_SIZE) {
  const handle = this.handles.get(oldestKey);
  if (handle) {
    destroyDetachedRouteHandle(handle);
    this.handles.delete(oldestKey);
  }
}

This feature is experimental and may change in future releases, but provides important memory management capabilities for applications that need fine-grained control over route lifecycle.

Standalone isActive Helper Function

Angular 21.1 introduces a new `isActive()` standalone function that creates a computed signal for tracking whether a specific URL or UrlTree is currently active. This function deprecates `Router.isActive()` and provides a more reactive, signals-based approach.

What makes this different:

– Returns a `Signal<boolean>` instead of a plain boolean

– Automatically reacts to router state changes

– Tracks `router.lastSuccessfulNavigation()` internally

– Reduces bundle size for apps not using this functionality

Usage:

import { Component, inject } from '@angular/core';
import { Router, isActive } from '@angular/router';

@Component({
  selector: 'app-navigation',
  template: `
    <nav>
      <a [class.active]="isHomeActive()">Home</a>
      <a [class.active]="isAboutActive()">About</a>
      <a [class.active]="isProductsActive()">Products</a>
    </nav>
  `
})
export class NavigationComponent {
  private router = inject(Router);
  
  // Creates computed signals that automatically update
  isHomeActive = isActive('/home', this.router, {
    paths: 'exact',
    queryParams: 'ignored',
    fragment: 'ignored',
    matrixParams: 'ignored'
  });
  
  isAboutActive = isActive('/about', this.router, {
    paths: 'exact',
    queryParams: 'ignored',
    fragment: 'ignored',
    matrixParams: 'ignored'
  });
  
  // Can also check URL patterns with query params
  isProductsActive = isActive('/products', this.router, {
    paths: 'subset',      // matches /products and /products/123
    queryParams: 'subset', // matches if query params are a subset
    fragment: 'ignored',
    matrixParams: 'ignored'
  });
}

Match Options:

– `paths`: `’exact’` | `’subset’` – How to match URL paths

– `queryParams`: `’exact’` | `’subset’` | `’ignored’` – How to match query parameters

– `fragment`: `’exact’` | `’ignored’` – How to match URL fragments

– `matrixParams`: `’exact’` | `’subset’` | `’ignored’` – How to match matrix parameters

The old `Router.isActive()` method is now deprecated and will be removed in future versions. The new standalone function integrates seamlessly with Angular’s signals-based reactivity and provides better tree-shaking benefits.

RedirectFunction Parameters Extension

The `RedirectFunction` now includes `paramMap` and `queryParamMap` parameters, providing easier access to route parameters during redirects:

const routes: Routes = [
  {
    path: 'old-user/:id',
    redirectTo: (params) => {
      const userId = params.paramMap.get('id');
      const source = params.queryParamMap.get('source');
      return `/users/${userId}?ref=${source}`;
    }
  }
];

A significant bug fix addresses an issue where `RouterLink` href wasn’t updating correctly with `queryParamsHandling`. This ensures that navigation links maintain proper query parameters across route changes.

Fixed scenario:

<a routerLink="/products" 
   [queryParams]="{ category: 'electronics' }"
   queryParamsHandling="merge">
  Products
</a>

Image Loader Enhancements

Angular’s built-in image loaders now support custom transformations, providing more flexibility when working with CDN providers.

Supported loaders:

– Cloudflare

– Cloudinary

– ImageKit

– Imgix

Example with custom transformations:

import { provideCloudflareLoader } from '@angular/common';

bootstrapApplication(AppComponent, {
  providers: [
    provideCloudflareLoader('https://cdn.example.com', {
      customTransformations: {
        quality: 'q_80',
        format: 'f_auto'
      }
    })
  ]
});

This enhancement allows teams to fine-tune image delivery based on their specific requirements while still leveraging Angular’s automatic image optimization features.

Compiler and Type Safety Improvements

Angular 21.1 includes several compiler enhancements that improve type safety and error detection:

Better AST Node Types

The compiler now provides more accurate types for expression AST nodes, leading to better TypeScript integration and IDE support.

Qualified Names in typeof

Support for qualified names in `typeof` type references improves TypeScript interoperability:

// Now supported in templates
type MyType = typeof MyNamespace.MyClass;

Improved Source Maps

The compiler produces more accurate span information for:

– `typeof` expressions

– `void` expressions

– Literal map keys

These improvements result in better error messages and debugging experiences.

Core Framework Improvements

Animation Memory Leak Fix

A critical fix addresses memory leaks in animations by properly cleaning up view data. This is particularly important for applications with frequent animations or long-running sessions.

Event Replay Memory Leak Fix

Another memory leak related to event replay has been fixed, improving application stability for server-side rendered applications using hydration.

SVG Security Enhancement

The framework now properly sanitizes sensitive attributes on SVG script elements, closing a potential security vulnerability.

Development Experience

Component Import Diagnostics

The compiler now ensures component import diagnostics are reported within the `imports` expression, making it easier to identify and fix import-related issues.

Stability Debugging with provideStabilityDebugging()

A new `provideStabilityDebugging()` utility helps identify why your application fails to stabilize within the expected timeframe (9 seconds). This is particularly valuable for debugging hydration issues, zoneless applications, or complex change detection scenarios.

Key Features:

– Automatically enabled in dev mode when using `provideClientHydration()`

– Can be manually added for production debugging or SSR without hydration

– Logs pending tasks to console when app doesn’t stabilize within threshold

– Works with Zone.js task tracking plugin for detailed macrotask information

Usage:

import { provideStabilityDebugging } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js/plugins/task-tracking'; // Optional: for Zone.js apps

bootstrapApplication(AppComponent, {
  providers: [provideStabilityDebugging()]
});

What it logs:

– `PendingTasks` keeping the application unstable with stack traces

– Macrotasks in the Angular Zone (when task-tracking plugin is imported)

– Stack traces showing where tasks were created

Example console output:

---- Application did not stabilize within 9 seconds ----

Macrotasks keeping Angular Zone unstable:
  Error: Task stack tracking error
    at setTimeout (myapp.component.ts:45)
    at MyComponent.ngOnInit (myapp.component.ts:42)

PendingTasks keeping application unstable:
  Error: Task stack tracking error
    at HttpClient.get (http-service.ts:23)
    at DataService.loadData (data.service.ts:15)

Important Notes:

– Neither the task tracking plugin nor this utility are removed from production bundles

– Use only for temporary debugging during development

– The utility warns if accidentally used in production mode

– Integrates with Zone.js `TaskTrackingZone` for enhanced debugging

This utility is particularly helpful when encountering the [NG0506](https://angular.dev/errors/NG0506) error (application remains unstable).

Migration Path

Most changes in Angular 21.1 are backward compatible. The main migration needed is updating `[field]` to `[formField]` for Signal Forms users:

# The Angular team will likely provide a migration schematic
ng update @angular/core

For applications not using Signal Forms or experimental features, Angular 21.1 can be adopted without code changes.

Browser Support Considerations

The experimental Navigation API integration works best in browsers with native Navigation API support:

– Chrome/Edge 102+

– Safari 17+ (partial support)

– Firefox: Under development

Applications will gracefully fall back to the History API in browsers without native support.

Conclusion

Angular 21.1 continues the framework’s evolution toward a more reactive, type-safe, and performant foundation. The template compilation enhancements reduce boilerplate, Signal Forms improvements polish the new forms experience, and router additions lay groundwork for future navigation features.

The most immediately useful features are:

1. Multiple switch case matching – cleaner template code

2. Spread operators – more expressive templates

3. [formField] directive – better Signal Forms naming

4. RouterLink fixes – more reliable navigation

For production applications, focus on the stable features (template enhancements, bug fixes) while keeping an eye on experimental features (Navigation API integration) for future adoption.

The consistent improvements in type safety and developer experience continue to make Angular a solid choice for enterprise applications requiring long-term stability and maintainability.

Share this post

Sign up for our newsletter

Stay up-to-date with the trends and be a part of a thriving community.