# 機能設計書 54-next/form（Form）

## 概要

本ドキュメントは、Next.jsの`next/form`（`<Form>`コンポーネント）の機能設計を記述する。`<Form>`コンポーネントはHTML標準の`<form>`要素を拡張し、プログレッシブエンハンスメント対応のフォーム送信とクライアントサイドナビゲーションを統合する。

### 本機能の処理概要

**業務上の目的・背景**：Webアプリケーションにおけるフォーム送信は、検索フォーム、フィルタリング、データ入力など多くの場面で使用される。従来のHTMLフォームはフルページリロードを伴うが、`<Form>`コンポーネントはフォーム送信をクライアントサイドナビゲーションに変換し、SPAライクなスムーズな操作体験を実現する。JavaScriptが無効な環境でも標準のフォーム送信として動作するプログレッシブエンハンスメントを保証する。

**機能の利用シーン**：検索フォーム（GETメソッドでのクエリパラメータ付きナビゲーション）、フィルタリングUI、ページネーション、並び替え操作など、フォーム送信結果を別ページ/同一ページに反映する場面で使用される。

**主要な処理内容**：
1. action属性がstring型の場合にナビゲーションフォームとして動作
2. フォームデータをURLSearchParamsに変換してナビゲーション先URLを生成
3. ルーターのpush/replaceメソッドでクライアントサイドナビゲーションを実行
4. App Router向けのプリフェッチ機能（action先のプリフェッチ）
5. 不正なフォーム属性（method, encType, target）の検出と警告
6. submitterのformAction属性による送信先オーバーライドのサポート

**関連システム・外部連携**：Pages Routerでは`RouterContext`経由でルーターと連携。App Routerでは別実装（fork）が使用される。

**権限による制御**：特にロールや権限による制御は行われない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 全画面で利用可能な汎用フォームコンポーネント |

## 機能種別

ナビゲーション / UIコンポーネント / フォーム処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| action | string \| function | Yes | フォーム送信先のパス/URLまたはServer Action関数 | 文字列の場合はURL解析可能であること |
| replace | boolean | No | history.replaceStateを使用するか（デフォルト: false） | actionがstringの場合のみ有効 |
| scroll | boolean | No | スクロール動作のオーバーライド（デフォルト: true） | actionがstringの場合のみ有効 |
| prefetch | false \| null | No | プリフェッチ制御（Pages Routerでは未サポート） | App Routerのみ |
| onSubmit | function | No | フォーム送信時のコールバック | 関数型 |

### 入力データソース

- HTMLフォーム要素のFormData
- RouterContext（Pages Router）からのルーターインスタンス

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| HTML form要素 | React.ReactElement | `<form>`要素としてレンダリングされるReact要素 |
| ナビゲーション実行 | void | ルーターのpush/replaceメソッド呼び出しによるクライアントサイド遷移 |

### 出力先

- DOMへの`<form>`要素レンダリング
- ルーターへのナビゲーション指示

## 処理フロー

### 処理シーケンス

```
1. コンポーネントマウント・Props受け取り
   └─ action, replace, scroll, prefetch等のPropsを分解
2. フォームタイプ判定
   └─ action が string => ナビゲーションフォーム / function => 通常フォーム
3. バリデーション（開発モード）
   ├─ actionのURL妥当性チェック
   ├─ prefetchの警告（Pages Router）
   └─ 不正Props（method, encType, target）の検出・削除
4. ナビゲーションフォームの場合
   ├─ addBasePathでaction URLにbasePath付加
   └─ onSubmitハンドラ設定
5. フォーム送信時
   ├─ ユーザーのonSubmitコールバック実行
   ├─ submitter属性チェック（formAction, formMethod等）
   ├─ createFormSubmitDestinationUrlでフォームデータをURLに変換
   ├─ event.preventDefault()でネイティブ送信防止
   └─ router.push/replace でクライアントサイドナビゲーション実行
```

### フローチャート

```mermaid
flowchart TD
    A[Form コンポーネントマウント] --> B{action の型}
    B -->|function| C[通常 form レンダリング]
    B -->|string| D[addBasePath 適用]
    D --> E[onSubmit ハンドラ設定]
    E --> F[ユーザーフォーム送信]
    F --> G{onSubmit コールバック}
    G --> H{defaultPrevented?}
    H -->|Yes| I[処理中断]
    H -->|No| J{submitter チェック}
    J --> K{unsupported attributes?}
    K -->|Yes| L[ネイティブ送信に委ねる]
    K -->|No| M{React client action?}
    M -->|Yes| N[ネイティブ送信に委ねる]
    M -->|No| O[createFormSubmitDestinationUrl]
    O --> P[event.preventDefault]
    P --> Q[router.push/replace]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-54-01 | GETメソッド専用 | ナビゲーションフォームはGETメソッドのみサポート | actionがstringの場合 |
| BR-54-02 | SearchParams上書き | action URLのクエリパラメータはフォームデータで上書きされる | HTML標準仕様に準拠 |
| BR-54-03 | ファイル入力非サポート | ファイル入力はname値（ファイル名）のみが送信される | actionがstringの場合 |
| BR-54-04 | 不正Props削除 | method, encType, targetは警告後に削除 | 開発モード |
| BR-54-05 | submitter formAction | submitterのformAction属性がフォームのactionをオーバーライド可能 | submitter要素が存在する場合 |

### 計算ロジック

- `createFormSubmitDestinationUrl`: FormDataをURLSearchParamsに変換し、action URLに付加。action URL内の既存クエリパラメータは上書き（HTML標準仕様準拠）

## データベース操作仕様

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | URL解析エラー | actionが不正なURLの場合 | Errorスロー: 'Cannot parse form action as a URL' |
| - | 開発警告 | prefetchがPages Routerで使用された | console.error |
| - | 開発警告 | method/encType/target等の不正Props | console.error + Props削除 |
| - | 開発警告 | actionにクエリパラメータが含まれる | console.warn |

### リトライ仕様

該当なし

## トランザクション仕様

該当なし

## パフォーマンス要件

- App Routerではaction先のプリフェッチが可能（Intersection Observer利用）

## セキュリティ考慮事項

- `hasReactClientActionAttributes`により`javascript:`プロトコルのformActionを検出し、クライアントアクションとして処理
- `checkFormActionUrl`でactionのURL妥当性を検証

## 備考

- Pages Router版とApp Router版で実装がforkされている（本ドキュメントはPages Router版を記述）
- `useFormStatus`とのReact Transition API統合は今後の課題（TODOコメントあり）

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | form-shared.tsx | `packages/next/src/client/form-shared.tsx` | **8-49行目**: FormProps型定義 - action, replace, scroll, prefetch, DISALLOWED_FORM_PROPS |

**読解のコツ**: `FormProps`は`InternalFormProps`として定義され、HTMLFormPropsからDisallowedFormProps（method, encType, target）をOmitしている。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | form.tsx | `packages/next/src/client/form.tsx` | **18-86行目**: Formコンポーネント本体 - forwardRefで定義 |

**主要処理フロー**:
1. **22行目**: `useContext(RouterContext)` でPages Routerを取得
2. **25行目**: `typeof actionProp === 'string'` でナビゲーションフォーム判定
3. **28-52行目**: 開発モードバリデーション
4. **55-62行目**: DISALLOWED_FORM_PROPSの検出と削除
5. **64-66行目**: 非ナビゲーションフォームは通常の`<form>`をレンダリング
6. **68行目**: `addBasePath(actionProp)` でbasePath付加
7. **70-85行目**: onSubmitハンドラ付きの`<form>`をレンダリング

#### Step 3: フォーム送信処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | form.tsx | `packages/next/src/client/form.tsx` | **90-169行目**: `onFormSubmit`関数 - 送信処理の中核 |
| 3-2 | form-shared.tsx | `packages/next/src/client/form-shared.tsx` | **51-101行目**: `createFormSubmitDestinationUrl`関数 - フォームデータからURL生成 |

**主要処理フロー**:
- **106-113行目**: ユーザーのonSubmitコールバック実行、defaultPrevented確認
- **127-149行目**: submitter属性チェック（formEncType, formMethod, formTarget, formAction）
- **152行目**: `createFormSubmitDestinationUrl`で最終URLを生成
- **155行目**: `event.preventDefault()` でネイティブ送信を防止
- **168行目**: `router[method](targetHref, undefined, { scroll })` でナビゲーション実行

#### Step 4: バリデーションユーティリティを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | form-shared.tsx | `packages/next/src/client/form-shared.tsx` | **103-126行目**: `checkFormActionUrl` - URL妥当性チェック |
| 4-2 | form-shared.tsx | `packages/next/src/client/form-shared.tsx` | **133-180行目**: `hasUnsupportedSubmitterAttributes`, `hasReactClientActionAttributes` |

### プログラム呼び出し階層図

```
Form (forwardRef コンポーネント)
    |
    +-- addBasePath() ........................ basePath 付加
    |
    +-- onFormSubmit() ....................... 送信イベントハンドラ
    |       |
    |       +-- hasUnsupportedSubmitterAttributes()  submitter 属性チェック
    |       +-- hasReactClientActionAttributes()     React Action 判定
    |       +-- createFormSubmitDestinationUrl() .... URL 生成
    |       |       +-- new FormData(formElement)
    |       |       +-- URLSearchParams.append()
    |       +-- router.push() / router.replace() ... ナビゲーション
    |
    +-- checkFormActionUrl() ................. 開発時 URL チェック
```

### データフロー図

```
[入力]                         [処理]                           [出力]

Props (action, ...) -------> Form コンポーネント ------------> <form> 要素
                              |
FormData (ユーザー入力) ----> createFormSubmitDestinationUrl -> targetUrl
                              |
RouterContext --------------> router.push/replace -----------> クライアントサイドナビゲーション
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| form.tsx | `packages/next/src/client/form.tsx` | ソース | Formコンポーネント本体（Pages Router版, 169行） |
| form-shared.tsx | `packages/next/src/client/form-shared.tsx` | ソース | 共有型定義・ユーティリティ（181行） |
| add-base-path.ts | `packages/next/src/client/add-base-path.ts` | ソース | basePath付加 |
| router-context.shared-runtime.ts | `packages/next/src/shared/lib/router-context.shared-runtime.ts` | ソース | RouterContext定義 |
