Angular v22 Deep-Dive: Signal Forms, Aria, httpResource, OnPush
Technical Deep-Dive · June 11, 2026

Angular v22: The Signal-First
Future Is Here

Angular v22 ships on June 3, 2026 with Signal Forms stable, Angular Aria accessibility primitives, declarative Signal-based data fetching, OnPush as default, and a Fetch-first HTTP client. Here's everything you need to know — with code examples, migration strategies, and practical adoption advice.

Oleg Maximov June 11, 2026 16 min read

Overview: What's New in Angular v22

Angular v22 was released June 3, 2026. It's the most significant Angular release since v17's standalone components — shifting the entire framework toward a signal-first architecture. Signal Forms graduate to stable, OnPush becomes the default change detection, the HTTP client uses Fetch by default, and the new Angular Aria module provides first-class accessibility. Released alongside is v22.0.1 (June 10) with security fixes including TransferState hardening and SVG attribute sanitization.

Stable

Signal Forms

Graduated from developer preview — production-ready reactive forms built on Angular Signals.

Stable

Angular Aria

First-class WCAG-compliant accessibility primitives — ARIA directives, keyboard navigation, screen reader support.

Stable

httpResource & rxResource

Declarative Signal-based data fetching with automatic loading/error states and chain() for dependent resources.

Breaking

OnPush as Default

Components without explicit changeDetection now default to OnPush. Automated migration via schematics.

Breaking

Fetch API as Default

HttpClient now uses FetchBackend by default. XHR mode opt-in via withXhr(). Deprecates withFetch().

Breaking

TypeScript 6+ & Node 22+

Dropped support for TypeScript 5.x and Node.js 20. Requires TS 6.0+ and Node.js v22+.

Stable

@Service Decorator

New dedicated decorator for injectable services with factory function type safety.

Breaking

ComponentFactory Removed

ComponentFactoryResolver and ComponentFactory removed. Pass component classes directly.

Let's go through each feature in depth — what it does, why it matters, and how to use it today.

1. Signal Forms — Production-Ready Reactive Forms

The biggest feature in Angular v22 is the graduation of Signal Forms from developer preview to stable. After months of refinement — including lazy field initialization, generic union support, debounced async validation, parse error signals, configurable submit behavior, and custom control reset propagation — Signal Forms are now ready for production workloads.

Signal Forms replace both template-driven and reactive forms with a unified, signal-based API. Instead of FormControl, FormGroup, and FormArray classes, you get reactive field primitives backed by Angular Signals — meaning automatic, granular change detection without zone.js polling.

Before (Reactive Forms)

export class LoginComponent {
  form = new FormGroup({
    email: new FormControl('', [Validators.required, Validators.email]),
    password: new FormControl('', [Validators.required, Validators.minLength(8)]),
  });

  get email() { return this.form.get('email'); }

  onSubmit() {
    if (this.form.valid) {
      this.authService.login(this.form.value);
    }
  }
}

After (Signal Forms)

import { signalForm, formField } from '@angular/forms';

export class LoginComponent {
  form = signalForm({
    email: formField('', { validators: [required, email] }),
    password: formField('', { validators: [required, minLength(8)] }),
  });

  // Form state is reactive via Signals
  emailError = computed(() => {
    const field = this.form.controls.email;
    if (field.touched() && field.invalid()) {
      return field.getError('email') ?? 'Invalid email';
    }
    return null;
  });

  onSubmit() {
    if (this.form.valid()) {
      this.authService.login(this.form.value());
    }
  }
}

Key differences: Signal Forms track validity, touched, dirty, and errors through Signals rather than observable streams. There's no .get() with string paths — you access fields as typed properties. The schema definition is compact and composable, supporting nested groups, dynamic arrays, and union types natively.

Signal Forms vs Reactive Forms — Feature Comparison

Feature Reactive Forms Signal Forms
Change Detection Trigger Zone.js (polling) Signal (push, granular)
Error Access Subscription to statusChanges Signal — field.invalid()
Async Validation AsyncValidatorFn + debounceTime validateAsync with debounce option
HTTP Validation Manual service calls validateHttp — built-in
Type Safety Partial Full — generic unions supported
Dynamic Arrays FormArray FieldArray — signal-based
Per-Field Errors form.get('field').errors field.getError() — type-safe
Lazy Init All controls created upfront Lazy field instantiation

2. Angular Aria — First-Class Accessibility

Angular v22 ships Angular Aria as a stable module — a comprehensive set of accessibility primitives that make WCAG compliance a built-in framework feature rather than a third-party concern.

Angular Aria includes directives for:

import { AriaModule } from '@angular/aria';

@Component({
  selector: 'app-modal',
  standalone: true,
  imports: [AriaModule],
  template: `
    <div role="dialog" ariaModal ariaLabelledBy="modal-title">
      <h2 id="modal-title">Confirm</h2>
      <p>Are you sure you want to delete this item?</p>
      <div class="actions" ariaKeyboardNav>
        <button (click)="confirm()">Delete</button>
        <button (click)="cancel()">Cancel</button>
      </div>
    </div>
  `
})
export class ConfirmModalComponent {}

The ariaKeyboardNav directive handles arrow key navigation among focusable children, which is essential for toolbars, menu bars, tab lists, and radio groups. Combined with ariaModal for focus trapping and ariaLiveAnnouncer for dynamic updates, Angular Aria eliminates the need for third-party accessibility wrappers like Reach UI or Radix.

3. httpResource — Declarative Signal-Based Data Fetching

httpResource and its sibling rxResource represent a paradigm shift in how Angular applications fetch and manage remote data. Instead of managing request lifecycle manually with subscriptions, loading flags, and error states, you declare the data dependency as a Signal — Angular handles the rest.

import { httpResource } from '@angular/common/http';

@Component({
  selector: 'app-user-profile',
  template: `
    @if (user.isLoading()) {
      <p>Loading...</p>
    } @else if (user.error()) {
      <p>Error: {{ user.error() }}</p>
    } @else {
      <h2>{{ user.value().name }}</h2>
      <p>{{ user.value().email }}</p>
    }
  `
})
export class UserProfileComponent {
  userId = input<number>();

  // Declarative — httpResource reacts when userId changes
  user = httpResource<User>(() => `/api/users/${this.userId()}`, {
    defaultValue: { name: '', email: '' }
  });
}

httpResource returns an object with three reactive properties: value (the data Signal), isLoading (a boolean Signal), and error (an error Signal). When the request URL changes (e.g., the userId input updates), the resource automatically re-fetches and transitions through loading → success/error states.

Dependent Resource Chaining with chain()

Real applications rarely fetch a single resource. httpResource.chain() lets you express dependent data fetching without nested subscriptions or manual coordination:

// Team details load automatically after selectedTeamId is known
team = httpResource<Team>(() => `/api/teams/${this.selectedTeamId()}`);

// Team members load when team data is available
teamMembers = this.team.chain(
      (team) => `/api/teams/${team.id}/members`,
      { defaultValue: [] as Member[] }
    );

// Team members' tasks load from members
teamTasks = this.teamMembers.chain(
  (members) => `/api/tasks?assigneeIds=${members.map(m => m.id).join(',')}`,
  { defaultValue: [] as Task[] }
);

Each chain() call creates a derived resource that automatically invalidates and re-fetches when its parent resource changes. The chain handles race conditions — if a parent re-fetches before a child resolves, the stale child request is cancelled automatically.

For Observable-based data sources, rxResource provides the same declarative API over arbitrary RxJS observables — useful for WebSocket streams, event emitters, or legacy service integrations.

4. OnPush as Default Change Detection

Starting in Angular v22, components with no explicit changeDetection setting default to ChangeDetectionStrategy.OnPush. This is a breaking change that aligns Angular with modern reactive patterns.

To preserve the old behavior, explicitly set:

@Component({
  selector: 'app-legacy',
  changeDetection: ChangeDetectionStrategy.Eager,  // was Default
  template: `...`
})
export class LegacyComponent {}

The ng update schematic automatically identifies components that relied on the old default and adds ChangeDetectionStrategy.Eager where needed. However, the long-term direction is clear: pair OnPush with Signals for optimal performance. Signals naturally trigger change detection only in the components that consume them, making zone.js increasingly optional.

If you've been using Signals, computed, and effect in your Angular 21 codebase, this change is transparent — your components already behave like OnPush because signal reads in templates are tracked and re-rendered granularly. The difference is now enforced at the component level, catching components that mutated state directly without going through Signals or immutables.

5. Fetch API as Default HttpClient

Angular v22 flips the default HTTP backend from XMLHttpRequest (XHR) to the modern Fetch API. The HttpClient now uses FetchBackend by default, bringing streaming response support, better error handling, and improved performance characteristics.

withFetch() is now deprecated — it was previously required to opt into the Fetch backend, but it's now the default and can be safely removed. If you need the XHR backend (e.g., for upload progress reporting), opt in explicitly:

// Default in v22 — Fetch is used automatically
provideHttpClient()

// Opt into XHR if you need upload progress callbacks
provideHttpClient(withXhr())

The schematics migration adds withXhr() automatically where provideHttpClient was previously called without arguments, preserving backward compatibility. New projects should remove withFetch() from their provider configuration.

Other HTTP improvements in v22:

6. TypeScript 6.0+ and Node.js 22+ Required

Angular v22 drops support for TypeScript 5.x (including TS 5.8 and 5.9) and Node.js 20. You must upgrade to:

This enables Angular to leverage TS 6.0's improved type inference, const type parameters, and the new using declarations for resource management. The compiler-cli also adds explicit support for Node.js 26's new APIs.

The ng update schematic adds "strictTemplates": true to your tsconfig and disables the nullishCoalescingNotNullable and optionalChainNotNullable diagnostics that the TS 6.0 upgrade may trigger on existing templates. You can disable these manually if needed.

7. Other Notable Changes

@Service Decorator

A new dedicated @Service decorator for injectable services provides better factory function type safety and marks the service as injectable with a clearer intent than the generic @Injectable({ providedIn: 'root' }) pattern. The decorator is marked as stable in v22.

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

@Service()
export class UserService {
  constructor(private http: HttpClient) {}

  getUsers(): Signal<ResourceState<User[]>> {
    return httpResource(() => '/api/users');
  }
}

injectAsync

A new injectAsync helper function enables asynchronous dependency injection — useful for lazy-loading services, dynamic providers, or dependencies that require async initialization.

Router Changes

paramsInheritanceStrategy now defaults to 'always', meaning route parameters are inherited from all parent routes. provideRoutes() has been removed — use provideRouter() or the ROUTES multi token. Component input binding gains options for unmatched input behavior.

Incremental Hydration Default

Angular v22 enables incremental hydration by default for server-side rendered applications. Instead of hydrating the entire page at once, the framework hydrates components as they become visible or interactive — reducing Time to Interactive (TTI) significantly.

Removed APIs

Angular Aria in the Changelog

While Angular Aria was developed over several releases, v22 finalises it as a stable, documented module. The changelog also notes an important fix: ARIA property bindings are no longer renamed to attributes (commit f008045ded), ensuring that dynamic ARIA bindings in templates work correctly without unexpected attribute expansions.

Migration Guide: Angular 21 → 22

Here's the step-by-step migration checklist for upgrading from Angular 21 to 22:

  1. Update Node.js to v22 LTS or higher
  2. Update TypeScript to v6.0+: npm install typescript@~6.0
  3. Run the update schematics: ng update @angular/core@22 @angular/cli@22 — this handles:
    • Adding ChangeDetectionStrategy.Eager where needed
    • Migrating provideRoutes()provideRouter()
    • Updating provideHttpClient configuration
    • Enabling strictTemplates and disabling nullable diagnostics
    • Adding withXhr() for upload progress users
  4. Replace ComponentFactory usages: pass component classes directly to ViewContainerRef.createComponent()
  5. Review form validation: min and max validators no longer accept string values — use numbers or null
  6. Remove withFetch() from provider config (it's now the default)
  7. Test with OnPush: if any components relied on the old default change detection for mutable updates, add explicit ChangeDetectionStrategy.Eager or migrate to Signals
  8. Verify template compatibility: data- prefixed attributes no longer bind inputs/outputs; in variables throw in template expressions; duplicate selectors trigger compile-time errors

FAQ

What is the most important new feature in Angular v22?
Signal Forms graduating to stable is the most significant change — it introduces a fully reactive, signal-based form control system that replaces the old template-driven and reactive forms with better type safety and performance. Combined with OnPush as the default change detection strategy, this shifts Angular firmly into a signal-first architecture.
What is Angular Aria and why is it important?
Angular Aria provides stable, first-class WCAG-compliant accessibility primitives. It ships as reusable directives for ARIA attributes, keyboard navigation, focus management, and screen reader announcements. This eliminates the need for third-party accessibility libraries and makes compliance an integral part of the framework rather than an afterthought.
How does httpResource differ from HttpClient in Angular v22?
httpResource is a new declarative, Signal-based HTTP data fetching utility that integrates directly with Angular's reactive system. It provides automatic loading/error/success states through Signals, supports dependent resource chaining via chain(), handles race conditions, and integrates with the transfer cache for SSR hydration. Unlike the imperative HttpClient, httpResource is composable and fits naturally into Angular's component model.
Does OnPush as the default change detection break existing components?
Components with no explicit changeDetection setting now default to OnPush. The Angular team provides an automated migration schematics via ng update that adds ChangeDetectionStrategy.Eager where needed. Components that relied on the default change detection for mutable state updates may need adjustment — either migrate to Signals or explicitly set ChangeDetectionStrategy.Eager.
How do I migrate from Angular 21 to Angular 22?
Run ng update @angular/core@22 @angular/cli@22. The migration schematics handle: adding ChangeDetectionStrategy.Eager where needed, migrating provideRoutes to provideRouter, updating TypeScript to v6+, and enabling strictTemplates. Manual steps include: removing deprecated ComponentFactoryResolver, migrating from withFetch (now default), and updating form validation if using string-based min/max. See the Angular Update Guide at angular.dev for the complete checklist.
Does Angular v22 require Node.js 22?
Yes. Angular v22 drops support for Node.js 20 and requires Node.js v22+ as well as TypeScript 6.0+. This aligns with the Node.js release cycle which moved Node 20 into maintenance-only mode earlier this year.
What new features does Angular v22 bring for forms?
Besides Signal Forms graduating to stable, Angular v22 adds: reloadValidation for manually triggering async validation, debounce option for validateAsync and validateHttp, FieldState.getError() for reading per-field errors without subscriptions, ngNoCva opt-out for ControlValueAccessors, template and reactive support for FormValueContainer (FVC), and support for binding number|null to input type text.

Should You Upgrade to Angular v22?

Yes — for most projects. The signal-first direction is clearly Angular's future, and v22 offers a stable foundation for that transition. Key considerations:

I've been building Angular applications since Angular 2 (2016) and have migrated codebases from v2 through v21. The v22 upgrade is one of the smoothest major transitions yet — the schematics are comprehensive, and the signal-first architecture genuinely improves developer experience and application performance. If you need help planning or executing the migration, reach out.

Contact

Need help with your Angular project?

I build production Angular applications and can help with v22 migration, architecture, or full-stack development. Free initial consultation.