以下では、DOMを用いた「バリデーション付きフォーム」の実装を、HTML標準の制約検証(Constraint Validation API)と、独自ロジック(カスタム検証・非同期検証)を交えて体系的に解説します。実装の目的は、入力エラーを早期に検出し、ユーザーに分かりやすく、かつアクセシブルにフィードバックすることです。最後に、実運用でのセキュリティ・UXの要点もまとめます。
1. まずはHTMLの標準バリデーションを使う
HTMLの属性を適切に指定すると、ブラウザ標準のバリデーションが有効になります。
-
required,minlength,maxlength,min,max,pattern -
type=email|url|number|tel|password|date|time|datetime-localなど -
標準の擬似クラス:
:valid,:invalid,:required,:optional,:in-range,:out-of-range
novalidate を付けるとブラウザのデフォルトエラーポップアップは抑制され、DOM(JavaScript)で制御しやすくなります。
簡易スタイル(標準疑似クラスで視覚フィードバック)
2. Constraint Validation APIの基礎
主要メソッド・プロパティ:
-
el.checkValidity():制約を満たしていればtrue。満たさなければfalse。 -
el.reportValidity():結果表示を伴うチェック(標準UIを出す)。novalidate時は通常使わない。 -
el.setCustomValidity(message):カスタムエラーメッセージ設定。空文字で解除。 -
el.validity:詳細な状態(valueMissing,typeMismatch,patternMismatch,tooShortなど)。
3. クライアントサイドのカスタム検証(同期)
以下は、入力イベントで逐次チェックし、エラーを各フィールド下に表示する例です。
ポイント:
-
setCustomValidity('')を先に呼び出し、前回のカスタムメッセージを必ずクリアする。 -
aria-invalid,aria-describedbyを適切に設定し、スクリーンリーダー配慮を行う。 -
送信時はすべてのフィールドを再評価して、最初のエラーにフォーカス。
4. 非同期検証(例: ユーザー名の重複チェック)
APIによる確認が必要な検証は、入力のたびに通信せず、デバウンスを挟みます。以下は概念例(実APIはダミー)。
5. サーバーサイド検証は必須
クライアントでいくら検証しても、改変やスクリプト送信を防げません。必ずサーバーで同等以上の検証を行い、エラー時はフィールドごとにメッセージを返す設計にします。返ってきたサーバーエラーをDOMにマッピングして表示すると、クライアントとサーバーの一貫性が保てます。
6. アクセシビリティとUXの要点
-
エラーは入力欄の直下にテキストで表示し、
aria-live="polite"で動的更新を支援。 -
labelとfor、idの対応を正しく設定。 -
可能なら、エラー時に短い説明文を併記(例: 期待フォーマット)。
-
フォーカス管理: 送信時は最初のエラーにフォーカス移動。
-
漢字氏名や多言語入力では IME 中の
inputイベントに注意(変換確定後の検証やcompositionendでのチェック)。 -
モバイル:
inputmode, 適切なtype(email,tel,number)でキーボード最適化。 -
逐次検証は過剰にならないよう、
inputでは軽量チェック、詳細はblurまたはsubmitで行うと負担が減ります。
7. よくある落とし穴
-
hidden/type="hidden"は制約検証の対象外。disabledも対象外。 -
display:noneの要素はフォーカス不可。エラー説明を不可視にしてしまわない。 -
patternは全文一致。部分一致を期待して誤る例が多い。 -
ローカライズ: 数値・日付のフォーマットはロケール差異に注意。
-
同期・非同期を混在させる際は、送信時の最終判定ですべてが解決済みであることを保証する(送信ボタンの一時無効化やローディング表示など)。
8. スキーマ駆動の検証(発展)
プロジェクト規模が大きい場合、DOM直書きではなく、スキーマ(例: JSON Schema)を用いて
-
ルール定義(型、必須、パターン、最小長など)
-
メッセージのローカライズ
-
同じルールをクライアント/サーバーで共有
といったアプローチが有効です。フォーム生成やルール変更の保守性が上がります。
9. セキュリティの観点
-
クライアント検証は利便性であり、安全性ではありません。必ずサーバーで再検証。
-
サーバーでは CSRF 対策、Rate Limiting、bot 対策(reCAPTCHA 等)を検討。
-
エラーには内部情報を含めない(スタックトレースやSQL情報など)。
-
パスワードはクライアントでもサーバーでもログに出さない。
10. まとまった実装サンプル(最小完全例)
以下は、標準属性+カスタム検証+送信時最終チェックを組み合わせた最小構成です。
まとめ
-
HTML標準属性で基本的な制約を定義し、DOMから Constraint Validation API を使って制御する。
-
入力中は軽量チェック、フォーカスアウトや送信時に厳密チェックを行う。
-
非同期検証にはデバウンスを導入し、送信時には未解決の検証が残らないよう制御する。
-
アクセシビリティ(
aria-*、エラーのテキスト表示、フォーカス移動)とモバイル入力最適化を忘れない。 -
セキュリティのため、必ずサーバー側でも検証し、両者を整合させる。
この流れをベースに、プロジェクト規模に応じてスキーマ駆動や共通ロジック化を取り入れると、保守性と品質が大きく向上します。
ChatGPT5 生成日:2025/09/11