この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 を意識して「いつ・どこに・どんなエラーを出すか」を設計する
という「フォームバリデーションの中級セット」を一通り経験しました。


