Summarize with AI:
Signals, Zoneless, declarative async resources: Angular 22 makes standard several features that help developers build better apps.
A few days ago, we checked out Google I/O 2026, and today we need to talk about our favorite framework: Angular. Why? Because version 22 is here!
Angular v22 is a major update focused on stability, performance and ergonomic APIs. It brings a more polished signal-driven platform and better data loading primitives that make modern apps feel faster and simpler to build.
Before we look at the most interesting changes, let’s talk about the foundation. Angular v22 stabilizes the features we have been testing in the last few versions. If you want to build a high-performance app today, these are the new standards.
Reactive Forms were great, but they often felt separate from the modern Signal-based reactivity. In v22, Signal Forms are officially stable.
What does this mean for us?
Do you remember HttpClient and the manual toSignal conversions? They worked, but they added extra code. Now we have httpResource.
It is the new standard for fetching data. It treats your HTTP requests as signals, automatically handling the loading, error, and data states for you.
Learn more: Dive deeper into Getting Started with httpResource API and learn more about Angular Signal Forms vs. Reactive Forms.
But what if your request depends on another signal? In v22, we have the new chain() method. It allows you to link resources together. If the first resource is loading, the second one waits automatically. This is a big win for complex data!
Wait, what if you are already using RxJS? Don’t worry, Angular has a solution for that too. Let’s see how v22 handles the transition from Observables to Resources.
A common question is: “Should I stop using RxJS?” The answer is no. Angular v22 introduces rxResource as the perfect partner for your existing Observable streams.
httpResource: Use this for standard API calls. It is optimized for the Fetch API and handles JSON automatically.rxResource: Use this when your data source is an existing Observable. It allows you to use the power of RxJS operators inside the clean, Signal-based Resource API.Now that we have our data fetching ready, how do we make sure our users and agents can navigate efficiently? Let’s talk about the new smart navigation features in the Router.
The Angular Router received some updates in v22 that solve common problems.
browserUrl input on RouterLink, you can show /profile while the router actually uses /users/123.But a great UI and smart routing mean nothing if the page is slow to load. This brings us to the most impressive performance update in v22: incremental hydration.
Server-Side Rendering (SSR) is no longer a problem. In v22, incremental hydration is the default.
Angular now loads your application in small parts as they become visible. Combined with resource caching, the client can use the data fetched on the server without making a second API call. The user sees the data instantly, and the “flicker” of reloading data is gone.
Learn more: Explore The New Angular Hydration for in-depth details.
But performance is also about how the browser handles changes. This is where the biggest change in Angular’s history reaches its peak.
For years, zone.js was the engine behind Angular’s change detection. With v22, Angular is now Zoneless by default.
By using ChangeDetectionStrategy.OnPush as the default for new components, we get:
If you have an older app, don’t worry! There is a migration tool that adds ChangeDetectionStrategy.Eager (the new name for the old behavior) so your app keeps working while you move to Signals.
Now, how do we make sure our fast code actually works? Let’s talk about the new speed king of testing.
Testing used to be the slow part of our work. Not anymore. Angular v22 officially replaces Karma/Jasmine with Vitest as the default test runner.
It is very fast and shares the same configuration as your build pipeline. Also, the new migrate-karma-to-vitest tool makes the change very easy, even for complex tests!
Do you want to try Vitest?
Building custom components with correct ARIA roles and focus management can be difficult. In v22, Angular Aria is officially stable.
Think of it as “headless accessibility.” It provides the logic you need to build your own accessible components. It handles the complicated parts of ARIA attributes and keyboard interactions for you.
Why does this matter for AI? Because accessible apps are much easier for AI Agents to understand!
Check this example about how to build accessible components with Angular Aria.
In v22, we finally have @boundary as part of the preview story. It is useful for future error-handling patterns. Here’s how @boundary works for error containment:
@Component({
selector: 'app-user-profile',
standalone: true,
template: `
<div>
<h2>User Profile</h2>
<p>{{ userData() }}</p>
</div>
`
})
export class UserProfileComponent {
userData = signal(null);
}
@Component({
selector: 'app-dashboard',
standalone: true,
imports: [UserProfileComponent],
template: `
<div>
<h1>Dashboard</h1>
@boundary on error {
<p>Failed to load user profile</p>
} {
<app-user-profile />
}
</div>
`
})
export class DashboardComponent {}
You no longer need a selector for a component that only lives in a route. It reduces extra code.
@Component({
standalone: true,
// No selector needed! Perfect for routes or dynamic loading
template: `<h3>I'm a lean, selectorless component!</h3>`
})
export class DetailViewComponent {}
The injectAsync() function allows us to load services only when they are needed. This keeps your app small and fast.
async onReportRequested() {
// We only load the heavy AnalyticsService when the user clicks!
const analytics = await injectAsync(AnalyticsService);
analytics.track('report_viewed');
}
Instead of just explaining features, let’s build a practical dashboard example that uses the stable core of Angular v22: @Service(), httpResource() and the new template syntax.
Want to follow along? You can clone the complete project from GitHub: angular-22-nba-finals. Just run
npm startand you’ll have the dashboard running locally.
Now, let’s create our service. We will use the new @Service() decorator (which replaces @Injectable()) and httpResource to fetch the games. Notice how httpResource handles loading and error states for you.
// src/app/nba.service.ts
import { Service } from '@angular/core';
import { httpResource } from '@angular/common/http';
export interface NbaGame {
id: number;
gameNumber: number;
homeTeam: string;
homeScore: number | null;
awayTeam: string;
awayScore: number | null;
status: 'Final' | 'Scheduled';
date: string;
location: string;
}
@Service()
export class NbaService {
// httpResource is the standard for fetching data
gamesResource = httpResource<NbaGame[]>('/api/nba-finals');
}
We display the data using the new @for block and keep the error handling inside the component template. This keeps the example focused on stable Angular v22 behavior.
// src/app/app.ts
@Component({
template: `
<app-dashboard></app-dashboard>
<router-outlet></router-outlet>
`
})
Our Dashboard component remains simple:
// src/app/dashboard.component.ts
import { Component, inject } from '@angular/core';
import { NbaService } from './nba.service';
@Component({
selector: 'app-dashboard',
standalone: true,
template: `
<div class="dashboard">
<h1>NBA Finals 2026: Knicks vs Spurs</h1>
@if (nbaService.gamesResource.isLoading()) {
<p>Loading game data...</p>
} @else {
<div class="cards">
@for (game of nbaService.gamesResource.value(); track game.id) {
<div class="card">
<div class="meta">Game {{ game.gameNumber }} • {{ game.date }}</div>
<div class="score">
{{ game.homeTeam }} {{ game.homeScore }} vs {{ game.awayScore }} {{ game.awayTeam }}
</div>
<div class="status">{{ game.status }}</div>
</div>
}
</div>
}
</div>
`
})
export class DashboardComponent {
nbaService = inject(NbaService);
}
Save changes and run ng server navigate in the browser and tada!!!

Done!! We play with the stable part of Angular v22 using @Service() for a clean singleton service definition, httpResource() for declarative, signal-based HTTP loading and @for with @if in templates to render loading and data states.
And, of course, AI is not forgotten by the Angular team. They updated and added new tools for Angular MCP and Skills. Let’s see them!
Of course, Angular continues embracing AI. The Angular MCP exposes app state and builds workflows for tools that understand Angular projects. That includes server-side MCP tools such as devserver.wait_for_build, devserver.start and devserver.stop.
Version 22 also introduces Agent Skills for Angular, a lightweight set of skill definitions that give AI assistants direct knowledge of modern Angular idioms and best practices. These skills are useful for teams that want to integrate agent-assisted coding into their workflow without pain.
Angular 22 is a declaration that the way we build for the web has evolved. And by using Signals, Zoneless performance and declarative async resources, we can build applications that are faster, simpler and easier to maintain.
This release is about making stable patterns:
httpResource() for fetch-heavy components.@Service() for singleton services.injectAsync() when you want to defer heavy service loading.@for and @if keep your view code readable.My advice is don’t just read this article—build something! Take the dashboard we sketched and turn it into an interactive experience with Progress Kendo UI for Angular AI Chat. A chat interface is a powerful way to explore the series score in real time and it’s a great way to test Angular 22 with a modern Kendo UI scenario.
Feel free to watch for all the new features in Angular 22:
Happy coding!
Dany Paredes is a Google Developer Expert on Angular and Progress Champion. He loves sharing content and writing articles about Angular, TypeScript and testing on his blog and on Twitter (@danywalls).