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

JavaScript
スポンサーリンク

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

3日目は「バリデーションの質を上げる日」です。
昨日までで、あなたはすでに

  • 入力中にエラーを動的に表示
  • touched(触ったかどうか)による UX 改善
  • 正規表現による基本チェック

を体験しました。

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

  • エラーの種類を増やす(複数条件のバリデーション)
  • エラーの優先順位を設計する(どのメッセージを出すか)
  • フィールドごとの状態とフォーム全体の状態を整理する
  • submit 制御をより堅牢にする

という「中級バリデーションの本質」に踏み込みます。


エラーの種類を増やす:複数条件をどう扱うか

バリデーションは「1つの条件」では終わらない

メールもパスワードも、実際には複数の条件があります。

メールなら:

  • 空でない
  • 形式が正しい
  • 長すぎない(UX 的に追加してもよい)

パスワードなら:

  • 空でない
  • 長さが足りている
  • 英字と数字を含む
  • 記号を許可するかどうか

これらを「どの順番でチェックするか」が UX に直結します。

エラーの優先順位を決める(重要)

例えばパスワードが空のときに、

「英字と数字を含めてください」
と出たら、ユーザーは混乱します。

だから、バリデーション関数は「優先順位の高い条件から順にチェック」します。

function validatePassword(value) {
  if (!value) {
    return "パスワードを入力してください。";
  }
  if (value.length < 8) {
    return "パスワードは8文字以上にしてください。";
  }
  if (!/[A-Za-z]/.test(value)) {
    return "英字を1文字以上含めてください。";
  }
  if (!/\d/.test(value)) {
    return "数字を1文字以上含めてください。";
  }
  return "";
}
JavaScript

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

  • 「最初に引っかかったエラーだけ返す」
  • 複数のエラーを一度に出さない(UX が悪くなる)

という設計です。


エラー状態を「フィールド単位」で管理する

state の errors を整理する

昨日の state はこうでした。

errors: {
  email: "",
  password: "",
  form: "",
}
JavaScript

今日はこれを「フィールド単位で完結する」ように扱います。

  • email のエラーは email のバリデーション関数だけが決める
  • password のエラーは password のバリデーション関数だけが決める
  • form のエラーは submit 時にだけ使う

この分離ができると、コードが一気に読みやすくなります。

touched と errors の関係を明確にする

UX 的に重要なのは、

  • touched が false のときはエラーを表示しない
  • touched が true のときは errors をそのまま表示する

というルールです。

render の中でこう書けます。

emailErrorEl.textContent =
  state.touched.email ? state.errors.email : "";

passwordErrorEl.textContent =
  state.touched.password ? state.errors.password : "";
JavaScript

これにより、

  • 初回は静か
  • 一度触ったら、リアルタイムでエラー更新

という自然な UX になります。


入力中のバリデーションを「より自然に」する

input と blur の役割を再確認する

昨日はこうでした。

  • blur → touched を true にする
  • input → touched が true のときだけエラー更新

今日はこれを「より自然に」します。

例:メール欄の改善版

emailInputEl.addEventListener("input", () => {
  state.email = emailInputEl.value;

  if (state.touched.email) {
    state.errors.email = validateEmail(state.email);
  }

  render();
});

emailInputEl.addEventListener("blur", () => {
  state.touched.email = true;
  state.errors.email = validateEmail(state.email);
  render();
});
JavaScript

ここでの UX のポイントは、

  • 入力中にエラーが出るのは「一度触った後だけ」
  • blur した瞬間に必ずエラーが出るので、ユーザーは気づきやすい

という点です。

パスワードも同じパターンで扱う

passwordInputEl.addEventListener("input", () => {
  state.password = passwordInputEl.value;

  if (state.touched.password) {
    state.errors.password = validatePassword(state.password);
  }

  render();
});

passwordInputEl.addEventListener("blur", () => {
  state.touched.password = true;
  state.errors.password = validatePassword(state.password);
  render();
});
JavaScript

submit 制御を「堅牢」にする

submit 時は「全フィールドを強制チェック」

入力中のバリデーションがあっても、submit 時には必ず全体をチェックします。

formEl.addEventListener("submit", (event) => {
  event.preventDefault();

  state.touched.email = true;
  state.touched.password = true;

  state.errors.email = validateEmail(state.email);
  state.errors.password = validatePassword(state.password);

  const hasError =
    state.errors.email || state.errors.password;

  if (hasError) {
    state.errors.form = "入力内容を確認してください。";

    if (state.errors.email) {
      emailInputEl.focus();
    } else if (state.errors.password) {
      passwordInputEl.focus();
    }

    render();
    return;
  }

  state.errors.form = "";
  state.isSubmitting = true;
  render();

  setTimeout(() => {
    state.isSubmitting = false;
    state.errors.form = "ログイン成功!(ダミー)";
    render();
  }, 800);
});
JavaScript

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

  • submit 時は touched を強制的に true にする
  • 最初のエラーにフォーカスを移す(UX の大事な要素)
  • isSubmitting で連打を防ぐ

という「実務でよく使うパターン」を体験できることです。


3日目のまとめと、明日へのつなぎ

今日あなたが身につけたのは、まさに「中級バリデーションの核」です。

  • 複数条件のバリデーションを優先順位付きで設計する
  • エラー状態をフィールド単位で管理する
  • touched を使って UX を自然にする
  • submit 時に全体チェック+フォーカス移動
  • バリデーション関数を純粋関数として設計する

明日(4日目)はここからさらに、

  • バリデーションの再利用性を高める
  • 複数フィールドを追加したときの設計の崩れにくさ
  • エラー表示のコンポーネント化(関数化)

など、「設計力」をさらに伸ばす方向に進みます。

もし余裕があれば、今日のコードで

  • メールを aaa@bbb にして blur
  • パスワードを abc123 にして blur
  • submit を押してフォーカス移動を確認

など、実際に触って UX の違いを感じてみてください。

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