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

JavaScript
スポンサーリンク

この7日間のゴールと全体像

この 7 日間は「ログインフォーム風のミニアプリ」を題材に、
メールアドレスとパスワードの入力チェックを通して、

  • 正規表現での形式チェック
  • エラー表示と submit 制御
  • ユーザー体験(UX)を意識したバリデーション設計

を身につけることがゴールです。

最終的には、次のようなフォームを作ります。

  • メール:形式チェック(xxx@yyy.zz のような形)
  • パスワード:長さ・文字種(英数字など)のチェック
  • 入力中にエラーが動的に表示される
  • エラーがある間は submit できない(ボタン無効 or 送信キャンセル)

1日目:フォームバリデーションの全体像と HTML の骨組み

フォームバリデーションとは何か

フォームバリデーションは「ユーザーの入力が条件を満たしているかをチェックする仕組み」です。
目的は、間違ったデータがサーバーに送られるのを防ぎ、ユーザーにすぐフィードバックを返すことです。

よくあるチェックは、必須チェック・形式チェック(メールなど)・文字数チェック・一致チェック(パスワード再入力)などです。

今回のアプリでは、クライアントサイド(ブラウザ側)の JavaScript でチェックを行い、
エラーがあればその場でメッセージを表示し、送信を止めます。

HTML の骨組みを作る

index.html を用意します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>フォームバリデーション練習</title>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    .field { margin-bottom: 16px; }
    .error-message { color: red; font-size: 12px; height: 16px; }
    .input-error { border-color: red; }
    button[disabled] { opacity: 0.5; cursor: not-allowed; }
  </style>
</head>
<body>
  <h1>ログインフォーム(バリデーション付き)</h1>

  <form id="login-form" novalidate>
    <div class="field">
      <label for="email">メールアドレス</label><br />
      <input id="email" type="email" />
      <div id="email-error" class="error-message"></div>
    </div>

    <div class="field">
      <label for="password">パスワード</label><br />
      <input id="password" type="password" />
      <div id="password-error" class="error-message"></div>
    </div>

    <button id="submit-button" type="submit">ログイン</button>
    <div id="form-message"></div>
  </form>

  <script src="app.js"></script>
</body>
</html>

ここではまだバリデーションはしていません。
ただし、エラーメッセージを表示するための <div id="xxx-error"> をあらかじめ用意しておくのが UX 的に重要です。


2日目:JavaScript の基本構造と「状態+render」の考え方

状態(state)でエラーを管理する

エラーメッセージを DOM に直接書き込むのではなく、
まず「状態」として JavaScript のオブジェクトに持ち、それをもとに画面を更新する設計にします。

const state = {
  email: "",
  password: "",
  errors: {
    email: "",
    password: "",
    form: "",
  },
  isSubmitting: false,
};
JavaScript

ここでのポイントは、エラーも state の一部として扱うことです。
「エラーがあるかどうか」「どんなメッセージか」を state から判断できるようにしておくと、
画面の更新ロジックがシンプルになります。

DOM の取得と render 関数の雛形

app.js に次を書きます。

const formEl = document.getElementById("login-form");
const emailInputEl = document.getElementById("email");
const passwordInputEl = document.getElementById("password");
const emailErrorEl = document.getElementById("email-error");
const passwordErrorEl = document.getElementById("password-error");
const submitButtonEl = document.getElementById("submit-button");
const formMessageEl = document.getElementById("form-message");

function render() {
  emailInputEl.value = state.email;
  passwordInputEl.value = state.password;

  emailErrorEl.textContent = state.errors.email;
  passwordErrorEl.textContent = state.errors.password;
  formMessageEl.textContent = state.errors.form;

  if (state.errors.email) {
    emailInputEl.classList.add("input-error");
  } else {
    emailInputEl.classList.remove("input-error");
  }

  if (state.errors.password) {
    passwordInputEl.classList.add("input-error");
  } else {
    passwordInputEl.classList.remove("input-error");
  }

  const hasError = Boolean(state.errors.email || state.errors.password);
  submitButtonEl.disabled = hasError || state.isSubmitting;
}
JavaScript

ここで重要なのは、

  • 「state を読んで UI を決める」一方向の流れ
  • エラーがあるかどうかで submit ボタンの disabled を制御していること

です。
submit を止める方法としては、event.preventDefault() で送信をキャンセルする方法もありますが、
UX 的には「そもそも押せない」状態にしておくのも有効です。


3日目:メールアドレスの正規表現チェック

正規表現の基本とメールパターン

正規表現(RegExp)は「文字列があるパターンに合っているか」をチェックするための表現です。
JavaScript では /パターン/ のように書き、regex.test(value) でマッチするか判定します。

メールアドレスの例として、次のようなパターンを使います。

const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
JavaScript

これはざっくり言うと、

  • @ の前に英数字や一部記号
  • @ の後にドメイン名
  • 最後に . と 2 文字以上のアルファベット

という形をチェックしています。

メールのバリデーション関数

メールのチェックを関数に切り出します。

function validateEmail(value) {
  if (!value) {
    return "メールアドレスを入力してください。";
  }
  if (!emailRegex.test(value)) {
    return "メールアドレスの形式が正しくありません。";
  }
  return "";
}
JavaScript

ここでのポイントは、

  • 「空かどうか」と「形式が正しいか」を分けてメッセージを出している
  • エラーがなければ空文字を返す(=エラーなし)

という設計です。

入力イベントで state を更新し、エラーを反映

メール入力欄にイベントを付けます。

emailInputEl.addEventListener("input", () => {
  state.email = emailInputEl.value;
  state.errors.email = validateEmail(state.email);
  render();
});
JavaScript

これで、入力のたびに

  • state.email が更新される
  • validateEmail でエラーが計算される
  • render でエラーメッセージと見た目が更新される

という流れになります。
リアルタイムバリデーションは UX を向上させる代表的なテクニックです。


4日目:パスワードのルール設計と正規表現

パスワードの条件を決める

ここでは例として、次のようなルールにします。

  • 8 文字以上
  • 英字と数字を少なくとも 1 文字ずつ含む

このようなルールは、正規表現で表現できます。

const passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/;
JavaScript

意味は、

  • (?=.*[A-Za-z]) 英字を少なくとも 1 文字含む
  • (?=.*\d) 数字を少なくとも 1 文字含む
  • [A-Za-z\d]{8,} 英字と数字だけで 8 文字以上

です。

パスワードのバリデーション関数

function validatePassword(value) {
  if (!value) {
    return "パスワードを入力してください。";
  }
  if (value.length < 8) {
    return "パスワードは8文字以上にしてください。";
  }
  if (!passwordRegex.test(value)) {
    return "英字と数字を少なくとも1文字ずつ含めてください。";
  }
  return "";
}
JavaScript

ここでも、「どの条件に引っかかったか」でメッセージを変えています。
ユーザーにとって「何がダメなのか」が明確になるので、UX 的に重要です。

パスワード入力イベントの処理

passwordInputEl.addEventListener("input", () => {
  state.password = passwordInputEl.value;
  state.errors.password = validatePassword(state.password);
  render();
});
JavaScript

これで、メールと同様にリアルタイムでエラーが表示されるようになります。


5日目:submit イベントの制御とエラーハンドリング

submit イベントでの最終チェック

リアルタイムでチェックしていても、submit 時にもう一度チェックするのが安全です。

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

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

  const hasError = Boolean(state.errors.email || state.errors.password);

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

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

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

ここでのエラーハンドリングのポイントは、

  • event.preventDefault() で送信を止める
  • state のエラーを更新してから render する
  • エラーがある場合はフォーム全体のメッセージを表示する

という流れです。

実際のアプリでは、この中でサーバーにリクエストを送りますが、
ここでは setTimeout で「送信中っぽさ」を演出しています。


6日目:UX を意識した改善(フォーカス・タイミング・メッセージ)

いつエラーを出すか(タイミング設計)

リアルタイムで常にエラーを出すと、入力途中でも真っ赤になってストレスになることがあります。
UX 的には、次のようなパターンがよく使われます。

  • 初回は blur(フォーカスが外れたとき)でエラーを出す
  • その後は input でも更新する
  • submit 後は全フィールドのエラーを表示する

中級の練習として、簡易版として「空の状態ではエラーを出さない」などの工夫を入れてもよいです。

例として、メールのバリデーションを少し変えます。

function validateEmail(value) {
  if (!value) {
    return "";
  }
  if (!emailRegex.test(value)) {
    return "メールアドレスの形式が正しくありません。";
  }
  return "";
}
JavaScript

そして submit 時には「必須チェック」を別途行う、という分担もできます。

フォーカス移動でエラー箇所に誘導する

submit 時にエラーがある場合、最初のエラーのフィールドにフォーカスを移すと UX が良くなります。

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

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

  render();
  return;
}
JavaScript

これで、ユーザーは「どこを直せばいいか」をすぐに理解できます。


7日目:設計の振り返りと応用の入り口

このフォームバリデーションの設計を整理する

今回のフォームバリデーションアプリは、ざっくり次のような構造になっています。

  • state
    入力値(email, password)、エラーメッセージ、送信中フラグを持つ。
  • バリデーション関数
    validateEmail, validatePassword が「入力値 → エラーメッセージ」を返す純粋関数。
  • render
    state を読み、入力欄の値・エラーメッセージ・見た目(クラス)・ボタンの disabled を更新。
  • イベントハンドラ
    input / submit などのイベントから state を更新し、バリデーション関数を呼び、render する。

この構造は、MDN や各種解説で紹介されている「クライアントサイドバリデーション」の基本と同じ方向性です。

応用の方向性

この設計を保ったまま、次のような機能を足すことができます。

  • パスワード確認欄(再入力)を追加し、「一致チェック」を入れる
  • 利用規約チェックボックスを追加し、「チェックされていないと submit できない」ようにする
  • フィールドごとに「OK」のときは緑色の枠やアイコンを表示する(ポジティブなフィードバック)
  • エラーをまとめて上部に一覧表示する(アクセシビリティ向上)

どれも、「state に何を持つか」「バリデーション関数をどう増やすか」「render でどう見せるか」の延長線上で考えられます。


まとめ

この 7 日間であなたは、

  • 正規表現でメール・パスワードの形式チェックを行う
  • エラーメッセージを state として管理し、動的に表示する
  • submit を制御し、エラー時に送信を止める
  • UX を意識して「いつ・どこに・どんなエラーを出すか」を設計する

という「フォームバリデーションの中級セット」を一通り経験しました。

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