今回はAngular 22で正式に導入された「Signal Forms」の機能をご紹介します。
目次
はじめに
Angularは、HTMLとデータ管理をカプセル化するコンポーネントベースのWebフレームワークで、エンタープライズ向けWebアプリケーション開発で広く利用されており、豊富なフォーム機能を備えています。最近では、その特徴を活かした新しいフォーム管理の概念「Signal Forms」がリリースされました。Signal Formsはシグナルと呼ばれる仕組みを利用することで、従来の方法よりもシンプルなコードでフォームを実装できるアプローチです。この記事では、Signal Formsの特長や既存のフォーム管理との違いを解説していきます。
Signal Formsとは

Signal FormsはAngularのフォーム管理手法の1つで、シグナルと呼ばれるリアクティブな状態管理の仕組みをベースに作られた新しい概念です。従来のReactive Formsと比べてシンプルなコードで実装できるデータモデルを中心とした仕組みで、Angular 21でDeveloper Previewとして導入され、Angular 22で正式版(Stable)となりました。
シグナルはAngular内の状態管理の仕組みで、カプセル化されたデータの変更を検出して通知したり、変更をトリガーに処理を実行する機能を備えています。Signal Formsは書き込み可能なシグナルをベースにフォームを作成します。
例えばSignal Formsを使ったフォームは、次のようにsignal関数でフォームデータを定義したシグナルをform関数に渡すことで生成できます。
export class LoginComponent {
loginModel = signal({
email: '',
password: '',
});
loginForm = form(this.loginModel);
}作成されたフォームモデルは次のようにディレクティブでHTMLにバインドできます。
<input type="email" [formField]="loginForm.email" />
<input type="password" [formField]="loginForm.password" />バリデーションや状態変更などのロジックはフォームモデル作成時にまとめて定義でき、冗長なコードやHTML側のロジックが削減され、よりシンプルなコードになります。
loginForm = form(this.loginModel, (fieldPath) => {
required(fieldPath.email, {message: 'Email is required'});
email(fieldPath.email, {message: 'Enter a valid email address'});
required(fieldPath.password, {message: 'Password is required'});
minLength(fieldPath.password, 8, {message: 'Password must be at least 8 characters'});
});従来のAngularのフォーム管理との違い
Signal Formsの登場以前には、Reactive Formsとテンプレート駆動フォームの2種類のフォーム管理によるフォーム実装が存在していました。
テンプレート駆動フォームはAngularの登場初期から使われており、HTML側に手軽にバリデーションなどのロジックを記述できる実装手法です。シンプルな入力フォームに適していますが、処理が複雑になるほどコード量が増えたり、テストコードを書くのが難しかったりといくつかの課題がありました。
Reactive FormsはFormControlやFormGroupを中心としたモデル駆動のフォーム管理手法で、Observable(RxJS)を利用してフォーム状態の変更を監視できます。ロジックがまとまることでテストコードが書きやすくなったり、データ型を明示できたりと、手軽さよりも大規模な開発への耐性が高くなっています。ただし、RxJSの理解の難しさや冗長なコードの多さが課題となっていました。
これらのフォーム管理の課題を解決すべく登場した手法がSignal Formsです。シグナルのデータモデルからAngular側でフォームが生成されるため、従来よりも見通しが良く少量のコードで実装できます。
| 項目 | テンプレート駆動 | Reactive Forms | Signal Forms |
|---|---|---|---|
| 学習コスト | 低 | 高 | 中 |
| 型安全性 | 低 | 高 | 高 |
| RxJS理解 | 不要 | 必要 | 基本不要 |
| 動的フォーム | △ | ○ | ○ |
| 記述量 | 少 | 多 | 少 |
Signal Formsの特長
宣言的なフォーム定義
Signal Formsでは、シグナルで定義するフォームデータを中心にフォームを構成する明快なアプローチを採用しています。form関数を経て自動生成されるフォームのフィールドツリーでは、シグナルに基づいて各フィールドの型やバリデーションが導出され、利用可能なオブジェクトが形成されます。そのため、開発者はデータ項目やそのバリデーションルールを明示するだけでよく、型安全性を確保しながらも短いコードで実装が可能です。また、これらのフォーム定義は一ヵ所にまとめられるためコードの見通しが良くなります。
複雑なフォームにも対応しやすい
Signal Formsは動的なフォームや複雑なバリデーションにも対応しやすい実装手法です。シグナルの変更はフィールドツリーに即座に反映されます。また、モデルの変更からフォーム構造を導出できるため、従来よりも動的フォームを扱いやすくなっています。また、フォームフィールド間が依存するような要件でも、シグナルの自動計算の仕組みを利用すればコードをシンプルに保てます。
Signal Formsを使ってみよう
ここからはSignal Formsを使ったフォーム作成手順を紹介していきます。なお、Signal Formsの作成にはNode.jsとAngular CLIがインストールされている必要がありますので、事前に準備しておきましょう。今回は下記の環境で使用していきます。
- Node.js v24.18.0
- Angular CLI v22.0.4
- angular/core v22
Signal Formsの実装
まずはプロンプトから新規プロジェクトを作成しましょう。
ng new angular-signal-forms続けて、次のコマンドを入力してフォーム用のコンポーネントを作成しましょう。
cd angular-signal-forms
ng g c loginコンポーネントが作成されたら、ロジックのコードが記載されたlogin.tsを下記のように書き換えます。
import {Component, signal} from '@angular/core';
import {email, form, FormField, minLength, required} from '@angular/forms/signals';
@Component({
selector: 'app-login',
imports: [FormField],
template: `
<form (ngSubmit)="onSubmit()">
<div>
<label>
Email
<input type="email" [formField]="loginForm.email" />
</label>
@if (loginForm.email().touched() && loginForm.email().invalid()) {
<p class="error">
@for (error of loginForm.email().errors(); track error) {
<span>{{ error.message }}</span>
}
</p>
}
</div>
<div>
<label>
Password
<input type="password" [formField]="loginForm.password" />
</label>
@if (loginForm.password().touched() && loginForm.password().invalid()) {
<p class="error">
@for (error of loginForm.password().errors(); track error) {
<span>{{ error.message }}</span>
}
</p>
}
</div>
<button type="submit" [disabled]="loginForm().invalid()">Sign In</button>
</form>
`,
})
export class LoginComponent {
loginModel = signal({
email: '',
password: '',
});
loginForm = form(this.loginModel, (fieldPath) => {
required(fieldPath.email, {message: 'Email is required'});
email(fieldPath.email, {message: 'Enter a valid email address'});
required(fieldPath.password, {message: 'Password is required'});
minLength(fieldPath.password, 8, {message: 'Password must be at least 8 characters'});
});
onSubmit() {
if (this.loginForm().valid()) {
const credentials = this.loginModel();
console.log('Submitting:', credentials);
}
}
}また、コンポーネントを表示させるために、既存のapp.htmlを下記のように書き換えておきましょう。
<router-outlet />さらに、作成したコンポーネントへのルーティング情報が記載されたapp.routes.tsも下記のように追記しましょう。
import { Routes } from '@angular/router';
import { LoginComponent } from './login/login';
export const routes: Routes = [
{ path: '', component: LoginComponent },
];Signal Formsで作成したフォームの表示
コードを修正できたら、ローカルサーバーで実行してみましょう。
npm startブラウザで「http://localhost:4200」にアクセスすると、下記のようなページが表示されます。

メールアドレスとパスワードを入力するとバリデーションが実装されていることがわかります。

さいごに
Signal Formsは、フォームのデータモデルを起点に構成される新しいAngularのフォーム実装方法です。これまで課題とされていたコードの複雑化が解消され、直感的かつ保守性の高いコードで実装できるようになりました。Signal Formsは特にシグナルベースで設計する新規アプリケーションとの相性が良く、既存アプリケーションでは要件や移行コストを考慮して採用を判断するとよいでしょう。
メシウスではAngularをはじめとした様々なJavaScriptフレームワークと一緒に使える、業務アプリ開発に最適なJavaScriptライブラリを提供しています。

無償のトライアル版や、ブラウザ上で手軽に試せるデモアプリケーションも公開しているので、こちらも是非ご覧ください。
