Angular v21 リリース、何か変わったのか
25年11月19日に、Angularの最新バージョン Angular v21 がついに公開されました!🥳
早速、v21の主な注目ポイントから確認し、詳細を見ていきましょう!
Angular v21 の主なハイライト
⚡️ シグナルで動く、新しいフォーム Signal Forms が登場
実験的な機能としてSignal Formsが導入されました。Signals上にフォームが作られるため、スケーラブルで構成しやすく、リアクティブなフォームの体験ができます。
✨ アクセシビリティを重視した Angular Aria の紹介
開発者プレビューとしてAngular Ariaがローンチされました。アクセシビリティを最優先に考えて作られたヘッドレスコンポーネントです。開発者は独自のスタイルをつけながら、誰でも使いやすいUIを楽に作れるようになりますので、これからの活用方法がお楽しみです。
🤖 AIエージェントとの連携がパワーアップ
AngularのMCP Serverがアップデートされ、安定版と実験版あわせて7つのツールが使えるようになりました。これで、LLM(大規模言語モデル)を使ったエージェントが、リリースされたばかりのAngularの機能をすぐに使えるようになります。
🧪 テストランナーは Vitest に決定
Angular CLIのデフォルトのテストランナーが Vitest に変わりました。Vitestは安定版として利用可能で、本番環境でも使えます。より高速でモダンなテスト実行が期待できます。
🚫 zone.jsがデフォルトから外れる
新しいAngularアプリを作る時、zone.jsが自動では含まれなくなりました。アプリをもっと軽く、パフォーマンス良くするための一歩ですね!
Web開発におけるAIの進化は目覚ましいですよね。AngularとAIエージェントの連携が強化されたのは、やっぱり見逃せないポイントです。
そして個人的には、もうSignalsなしではいられない体になっているので(笑)、シグナルフォームの登場は本当に嬉しいです😄
Karmaが非推奨になってから2-3年ほど?デフォルトのテストランナーが不在でしたが、今回ついに Vitest が選ばれたことは、開発者としても喜ばしく思っています。
それでは、気になるところを一つずつ詳しく見ていきましょう!
Signal Form
従来のフォーム開発では、FormGroupやFormControlを使った複雑なボイラープレートコードが必要でした。しかし、Signal Formsでは、フォームの状態がシグナルとして定義されるため、バインドされたフォームのフィールドと自動で同期します。
Signal Formsでは、フォームの状態がシグナルとして定義されます。このシグナルは、バインドされたフォームのフィールドと自動で同期します。
これにより、完全に型安全な開発が可能になります。さらに、ControlValueAccessorを使わなくてもカスタムコンポーネントにバインドできるようになり、人間工学に基づいた、より使いやすい開発体験が実現します。
使い方
Signal Forms のコアな使い方は、わずか3つのステップで実現できます。
1. モデルとFieldTreeの作成
まず、フォームのデータを保持するデータモデルをsignal()で定義します。次に、このモデルを form() 関数に渡して FieldTree を作成します。
// データモデルの定義
const loginModel = signal<LoginData>({
email: '',
password: '',
});
// FieldTreeの作成
const loginForm = form(this.loginModel);
2. HTMLへのバインド
HTML の入力要素に[field]ディレクティブを使って、作成したFieldTreeのフィールド(例: loginForm.email)をバインドします。これでデータモデルとUIの双方向バインディングが完了します。
<input type="email" [field]="loginForm.email" />
<input type="password" [field]="loginForm.password" />
3. 値の読み書き
フィールドの現在値は、field().value()シグナルでリアクティブに参照できます。また、field().value.set('new value')のような形で値を更新することも可能です。
バリデーションと状態管理
Signal Forms は、組み込みのバリデーターと、Field State Signalsによって、強力な状態管理を提供します。
バリデーションの追加
バリデーションルールを追加するには、form()関数の第2引数にスキーマ関数を渡します。この関数内で、required(), email(), minLength() などのバリデーターをフィールドに適用します。
また、オプションオブジェクトを渡すことで、エラーメッセージをカスタマイズできます。
const loginForm = form(this.loginModel, (schemaPath) => {
// 必須チェックとカスタムメッセージを設定
required(schemaPath.email, {message: 'Email is required'});
// メールアドレス形式のチェック
email(schemaPath.email, {message: 'Enter a valid email address'});
});
Field State Signals
各フォームフィールドは、field()関数を通じて、その状態を知らせるリアクティブなシグナルを公開しています。これにより、UIで検証結果や操作状態を簡単に表示できます。
| 状態シグナル | 説明 |
|---|---|
valid() |
フィールドが全てのバリデーションルールをパスしていれば true |
touched() |
ユーザーがフィールドにフォーカスした、フォーカスを外したら true |
dirty() |
ユーザーがフィールドの値を変更したら true |
disabled() |
フィールドが無効な状態なら true |
readonly() |
フィールドが readonly の状態なら true |
pending() |
非同期バリデーションが進行中なら true |
errors() |
バリデーションエラーのリスト(kind及びmessageプロパティを含む)を返す |
サンプルコード[1]
<form (submit)="onSubmit($event)">
<div>
<label>
Email:
<input type="email" [field]="loginForm.email" />
</label>
@if (loginForm.email().touched() && loginForm.email().invalid()) {
<ul class="error-list">
@for (error of loginForm.email().errors(); track error) {
<li>{{ error.message }}</li>
}
</ul>
}
</div>
<div>
<label>
Password:
<input type="password" [field]="loginForm.password" />
</label>
@if (loginForm.password().touched() && loginForm.password().invalid()) {
<div class="error-list">
@for (error of loginForm.password().errors(); track error) {
<p>{{ error.message }}</p>
}
</div>
}
</div>
<button type="submit">Log In</button>
</form>
import {Component, signal, ChangeDetectionStrategy} from '@angular/core';
import {form, Field, required, email} from '@angular/forms/signals';
interface LoginData {
email: string;
password: string;
}
@Component({
selector: 'app-root',
templateUrl: 'app.html',
imports: [Field],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class App {
loginModel = signal<LoginData>({
email: '',
password: '',
});
loginForm = form(this.loginModel, (schemaPath) => {
required(schemaPath.email, {message: 'Email is required'});
email(schemaPath.email, {message: 'Enter a valid email address'});
required(schemaPath.password, {message: 'Password is required'});
});
onSubmit(event: Event) {
event.preventDefault();
// ログインのロジックをこちらで実行する
const credentials = this.loginModel();
console.log('Logging in with:', credentials);
// e.g., await this.authService.login(credentials);
}
}
Angular Aria
ウェブアクセシビリティ(Web Accessibility)の確保は、全ての人にとって使いやすいデジタル体験を提供するために不可欠です。しかし、W3Cのアクセシビリティガイドライン(Web Content Accessibility Guidelines, WCAG)に完全に準拠したコンポーネントをゼロから実装するのは、多大な労力と専門知識が必要です。
そんな課題を解決してくれるのが、Angular Aria です。

Angular Ariaは、一般的なWAI-ARIAパターンを実装したヘッドレスでアクセシブルなディレクティブの集まりです。ヘッドレス(Headless)というのは、見た目(HTML構造やCSSスタイル)を持たない、機能(ロジック)だけを提供するという意味です。
こういうディレクティブが複雑なアクセシビリティ要件、すなわちキーボード操作、ARIA属性、フォーカス管理、スクリーンリーダーへの対応などを引き受けてくれます。
プロジェクトに導入するのは非常にシンプルです。
npm install @angular/aria
インストール後、Angular Ariaの利用方法やコード例を詳しく知りたい方は、ぜひこちらの公式ガイドをチェックしてみてください。
ガイドには、すべてのコンポーネントの使い方やコード例に加え、様々なデザイン(スキン)のデモとコードが掲載されています。気に入った見た目があれば、コピー&ペーストですぐに試すことができます。
Angularチームでは以下の三つの便利なツールを提供しています。
1. Angular Aria
- アクセシブルなヘッドレスコンポーネントが手に入ります。見た目(スタイル)は完全に自由に、好きなようにカスタマイズしたい場合に最適です。
2. Angular CDK
- Drag and Drop のような動作のプリミティブ(基本機能)が必要な場合に利用します。独自のカスタムコンポーネントを構築する際に、基本となる振る舞いだけを取り込めます。
3. Angular Material
- Material Designの原則に基づいた、すぐに使える(見た目が完成している)コンポーネントのフルライブラリが欲しい時に最適です。独自のテーマを使って、コンポーネントをカスタマイズすることも可能です。
Angular Ariaは、独自の見た目(カスタムスタイリング)を持ちながら、高いアクセシビリティを実現したい場合に真価を発揮します。デザインシステムや、厳密なブランド要件がある企業向けのライブラリを作る時に特に便利です。
逆に、見た目が完成しているコンポーネントがすぐに欲しい時や、シンプルなフォームにはAngular Materialなどの既存ライブラリやネイティブHTMLを使う方が効率的だと思います。
AIエージェントとの連携
Signal FormsやAngular Ariaのような最新機能が出ても、「使っているAIエージェントが、その新しい機能を知らないのでは?」と心配になるかもしれません。
でも、この点についてもAngularチームがしっかり対応してくれました!
Angular v21の大きなハイライトの一つとして、AIエージェントとの連携が大幅に強化されています。これを支えているのが、Angular CLIに組み込まれている MCP Server(Multi-Context Protocol server)です。このMCP Serverが、今回ついに安定版として公開されました。
MCP serverが最新情報を提供する
AIエージェントがAngular開発を的確にサポートするには、最新のAngularの知識と開発プロジェクト固有の情報が不可欠です。
ChatGPTなどのLLM(大規模言語モデル)は、学習した時点までの情報しか持ってない「ナレッジ・カットオフ (Knowledge Cutoff)」と課題があります。
しかし、MCP Serverを使うことで、そんな心配は無用です。エージェントはリアルタイムで最新情報を取得できるので、リリース直後の新機能もすぐに使えます。
例えば「Angular Ariaを使って、アクセシブルなメニューを作ってほしい」とAIエージェントに依頼すると、どうなるでしょうか?
- エージェントは、コード例を検索するための
find_examplesツールを呼び出します。 - MCP Serverが、リリースされたばかりのAngular Ariaのコード例を取得します。
- エージェントは、この最新コードを基に、あなたのプロジェクトに最適なコードを生成します。
このように、LLMの知識が古くても、AIエージェントがすぐに最新機能を使った開発をサポートしてくれるため、新機能のキャッチアップや導入にかかる手間が大幅に削減されます。
Angular MCPの詳しい利用方法やセットアップ手順は、こちらの公式ガイドで確認できますので、ぜひチェックしてみてください。
デフォルトランナー Vitest
2023年、Karmaが非推奨となって以来、Jest、Web Test Runner、そしてVitestなど、様々な新しいテストツールが検討されてきました。
そしてついに、コミュニティからの肯定的なフィードバックを受け、Vitestを新しいデフォルトのテストランナーとして採用することが決定しました!Angular v21で安定版としてリリースされたとのことです!🎉
新しいプロジェクトですぐに使える
新しいAngularアプリケーションでVitestを使うのはとても簡単です。
プロジェクト作成後、単にng testコマンドを実行するだけで、Vitestがテストを実行してくれます。
既存プロジェクトへの影響は?
Vitestが新しいデフォルトになりましたが、Angularチームは引き続きKarmaとJasmineを完全にサポートしてくれるようです。既存のアプリケーションをすぐに移行する必要はないので、ご安心ください。
もし既存のアプリケーションをVitestに移行したい場合は、実験的な移行機能が利用できます。以下の Schematic コマンドを実行することで、テストが自動的にVitest形式にリファクタリングされます。
ng g @schematics/angular:refactor-jasmine-vitest
今後のテスト戦略について
Vitestのサポートが安定版になったことに伴い、これまで実験的にサポートしていたWeb Test RunnerとJestのサポートは非推奨となり、v22で削除される予定です。
引き続きJestを利用したいチームはjest-preset-angularやNx Jest pluginといったコミュニティ主導の代替ソリューションの利用が推奨されています。
zone.jsが不要に
Angularはこれまで長年にわたりzone.jsを使用して、アプリケーション内の変更検知(Change Detection)を行ってきました。この仕組みによって、ユーザー操作などのイベント発生時に関連するテンプレートが自動で更新される機能を実現してきました。
しかし、zone.jsは特に大規模で複雑なアプリケーションにおいて、パフォーマンスのボトルネックとなる課題も抱えていました。
最新のAngularではsignalsが状態管理を担うようになり、zone.jsを使用しない「zoneless」な変更検知は、v18で実験的に導入された後、v20で開発者プレビューを経て、v20.2で安定版になりました。
そのため、v21からはzone.jsは新規アプリケーションにデフォルトでは含まれなくなります。
zoneless化のメリット
zoneless 変更検知を有効にすることで開発者は多くのメリットを実感できます。
- パフォーマンス向上: Core Web Vitals の改善につながります。
- より簡単なデバッグ: 変更検知の仕組みが分かりやすくなります。
- バンドルサイズの削減: アプリケーションが軽量化されます。
- エコシステムとの互換性向上: ネイティブの
async/awaitが使えるなど、外部ライブラリとの連携も容易になります。 - 制御性の向上: 開発者が変更検知のタイミングをより細かくコントロールできます。
既存アプリケーションの対応について
zonelessが新しいデフォルトになりますが、既存のアプリケーションのユーザー向けには、Angularの公式ドキュメントに移行手順が用意されています。zoneless化を目指して、移行を行いたい方はガイドラインの方を確認し確認ださい。
その他、変更点
...と、ここまで主要な機能を見てきましたが、Angularチームはこれ以外にも、注目すべきいくつかの改善を実現してくれました。
CLDRライブラリのサポートを更新
CLDR(Unicode Common Locale Data Repository)のライブラリサポートがv41からv47にアップデートされました。通貨や日付などのフォーマットがより正確に最新のものになります。
テンプレート内で正規表現が使えるように!
テンプレート内で正規表現(Regular Expression)を直接使えるようになりました!特に @let ブロックと組み合わせることで、データのバリデーションなどが非常にシンプルに書けます。
@let isValidNumber = /\d+/.test(someValue);
@if (!isValidNumber) {
<p>{{someValue}} は有効な数値ではありません!</p>
}
Signals用のビルトインフォーマッタが登場
signals用のビルトインフォーマッタが組み込まれたとのことです。ChromeやFirefoxなどのブラウザでカスタムフォーマッタを有効にすれば、デバッグ時にsignalsの中身をより分かりやすく確認できるようになります。

@deferトリガーのカスタマイズが可能に
@deferブロックのon viewportトリガーで、IntersectionObserverのオプションをカスタマイズできるようになりました。例えば、rootMarginを設定して、コンテンツがビューポートに入る前に少し早めにロードを開始することができます。
@defer (on viewport({trigger, rootMargin: '100px'}) {
<section>Content</section>
}
最後に
Angular v21は、Signal Formsの導入、Vitestのデフォルト化、zone.jsのデフォルトからの分離など、開発体験を根本的に向上させる大きな変更を含んでいますね。
ぜひ、この最新版を試して、新しいAngular開発を楽しみましょう!私もワクワクしています😄
最後まで読んでいただき、ありがとうございました。
Discussion