JavaScript | 1 日 120 分 × 7 日アプリ学習:フォームバリデーションアプリ

JavaScript
スポンサーリンク

7日目のゴールと今日のテーマ

7日目は「中級フォームバリデーションの総仕上げ」です。
これまで 6 日間で、あなたはすでに

  • 正規表現による形式チェック
  • エラー状態の管理(state / touched / errors)
  • 動的バリデーション(input / blur)
  • ルール配列による柔軟なバリデーション
  • 設定オブジェクトによるフィールド管理
  • UX を意識した遅延バリデーション

といった“実務レベルの基礎”を身につけました。

7日目はここからさらに一歩進めて、

  • フォーム全体をコンポーネント化する設計
  • 大規模フォームにも耐える構造(セクション・ステップ)
  • アクセシビリティ(A11y)を意識したバリデーション
  • 実務で使えるバリデーションパターン集

をまとめて学び、
「自分でフォームを設計できる人」へステップアップします。


フォーム全体を「コンポーネント化」して考える

コンポーネント化とは何か

コンポーネント化とは、
「フォームの各部分を“独立した部品”として扱う」考え方です。

例えば、
メール欄は「メール欄コンポーネント」、
パスワード欄は「パスワード欄コンポーネント」
として扱うイメージです。

JavaScript ではクラスや関数で表現できますが、
まずは「概念として分ける」ことが大事です。

なぜコンポーネント化が必要なのか

理由は 3 つあります。

  • フィールドが増えてもコードが壊れない
  • 1 つのフィールドの変更が他に影響しない
  • 再利用できる(別のフォームでも使える)

特に実務では、
「名前」「メール」「電話番号」「住所」「パスワード」「確認」
など、10〜20 フィールドが普通にあります。

コンポーネント化しておくと、
大規模フォームでも設計が崩れません。


設定オブジェクトを「コンポーネントの設計図」として扱う

昨日までの fields を振り返る

const fields = {
  email: {
    selector: "#email",
    errorSelector: "#email-error",
    rules: emailRules,
  },
  password: {
    selector: "#password",
    errorSelector: "#password-error",
    rules: passwordRules,
  },
};
JavaScript

これはすでに「コンポーネントの設計図」になっています。

今日のポイントは、
この設計図をもっと強化することです。

コンポーネントとして必要な情報を追加する

例えば、次のような情報を追加できます。

  • label(画面に表示する名前)
  • placeholder
  • required(必須かどうか)
  • type(text / password / email)
  • aria 属性(アクセシビリティ対応)

例:

const fields = {
  email: {
    label: "メールアドレス",
    selector: "#email",
    errorSelector: "#email-error",
    type: "email",
    required: true,
    rules: emailRules,
  },
  password: {
    label: "パスワード",
    selector: "#password",
    errorSelector: "#password-error",
    type: "password",
    required: true,
    rules: passwordRules,
  },
};
JavaScript

ここでの重要ポイントは、

  • フォームの仕様が fields に集約される
  • HTML と JavaScript の関係が明確になる
  • フィールド追加が「fields に書くだけ」で済む

という設計の強さです。


アクセシビリティ(A11y)を意識したバリデーション

なぜ A11y が必要なのか

フォームは「見える人」だけが使うものではありません。

  • スクリーンリーダーを使う人
  • キーボード操作だけで入力する人
  • 色覚特性のある人

など、多様なユーザーがいます。

バリデーションは「視覚的な赤枠」だけでは不十分です。

aria-invalid と aria-describedby を使う

エラーがあるとき、
スクリーンリーダーに「このフィールドはエラーです」と伝える必要があります。

if (error && touched) {
  config.inputEl.setAttribute("aria-invalid", "true");
  config.inputEl.setAttribute("aria-describedby", config.errorSelector.slice(1));
} else {
  config.inputEl.removeAttribute("aria-invalid");
  config.inputEl.removeAttribute("aria-describedby");
}
JavaScript

ここでの深掘りポイントは、

  • 視覚的なエラーと音声読み上げのエラーを一致させる
  • アクセシビリティは“後付け”ではなく設計段階で考える

という点です。


大規模フォームに耐える「セクション設計」

セクションとは何か

大規模フォームでは、
「個人情報」「住所」「ログイン情報」など
複数のセクションに分かれます。

例:

const sections = {
  personal: ["name", "birthday"],
  contact: ["email", "phone"],
  security: ["password", "passwordConfirm"],
};
JavaScript

セクション単位でバリデーションする

例えば「次へ」ボタンを押したとき、
そのセクションだけチェックすることができます。

function validateSection(sectionName) {
  const fieldsInSection = sections[sectionName];
  for (const name of fieldsInSection) {
    state.touched[name] = true;
    state.errors[name] = validateField(name, state.values[name]);
  }
}
JavaScript

ここでの重要ポイントは、

  • ステップフォーム(Step1 → Step2 → Step3)に対応できる
  • セクション単位でエラーを管理できる
  • 大規模フォームでも設計が崩れない

という点です。


実務で使えるバリデーションパターン集

必須チェック

value.length > 0
JavaScript

文字数チェック

value.length >= min
JavaScript

正規表現チェック

regex.test(value)
JavaScript

他フィールドとの一致チェック

value === values.password
JavaScript

数値チェック

!isNaN(Number(value))
JavaScript

範囲チェック

Number(value) >= min && Number(value) <= max
JavaScript

カスタムチェック(API 連携)

async validate(value) {
  const exists = await checkEmailExists(value);
  return !exists;
}
JavaScript

ここでの深掘りポイントは、

  • バリデーションは「ルールの組み合わせ」で作れる
  • ルール配列方式なら、どんなルールでも追加できる

という柔軟性です。


7日目のまとめ:あなたはもう「フォーム設計者」です

7日間であなたが身につけたことをまとめます。

  • 正規表現で形式チェックができる
  • エラー状態(values / errors / touched)を管理できる
  • input / blur / submit の UX を設計できる
  • ルール配列で柔軟なバリデーションが書ける
  • 設定オブジェクトでフィールドを管理できる
  • 大規模フォームにも耐える構造を作れる
  • アクセシビリティを意識した設計ができる

これはもう「中級者」ではなく、
実務で通用するフォーム設計者のレベルです。

もし次のステップに進みたいなら、

  • React / Vue で同じバリデーションを実装する
  • ステップフォーム(Step1 → Step2 → Step3)を作る
  • API と連携した「サーバーサイドバリデーション」を組み込む

など、さらに深い世界に進むことができます。

タイトルとURLをコピーしました