はじめに
前回記事のボタンを押してからバリデーション実施では、大量のエラーがどっと出ると一つ一つ直していくのは大変です。リアルタイムバリデーションなら、入力中にすぐ「何を直せばよいか」を示すことができます。
今回は、リアルタイムバリデーションの実装方法をLogとして記載していきたいと思います。
基礎から体系的に学びたい方にはこちらの本がおすすめです 👉
1冊ですべて身につくJavaScript入門講座
リアルタイムバリデーションとは
リアルタイムバリデーションとは、ユーザーが入力している最中(キー入力・貼り付け・フォーカス移動など)に即時でチェックを走らせ、エラーやヒントを表示する手法です。
メリット
- 即時フィードバックが可能:送信前に間違いに気づくことができる
- 修正コストの軽減:どの条件に引っかかったかがすぐわかり修正できる
デメリット
- 過剰なアラートは逆効果:入力途中の「未完成」を即エラー扱いしない工夫が必要となる(デバウンスや初回はblurで判定などの工夫)
- パフォーマンス低下:高頻度の検証は負荷に注意(正規表現や外部API照会はデバウンス/スロットリング)
リアルタイムバリデーションの実装方法
htmlとJavaScriptを使用して、簡単な実装例を試してみます。
html
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<title>リアルタイムバリデーション</title>
<link rel="stylesheet" href="css/realvalid.css" />
<script src="js/realvalid.js" defer></script>
</head>
<body>
<form id="signupForm" novalidate>
<div class="field">
<label for="username">ユーザー名(3文字以上)</label>
<input id="username" name="username" type="text" required />
<p id="usernameError" class="error" aria-live="polite"></p>
</div>
<div class="field">
<label for="email">メールアドレス</label>
<input id="email" name="email" type="email" required />
<p id="emailError" class="error" aria-live="polite"></p>
</div>
<div class="field">
<label for="age">年齢(0〜120)</label>
<input id="age" name="age" type="number" inputmode="numeric" min="0" max="120" required />
<p id="ageError" class="error" aria-live="polite"></p>
</div>
<div class="field checkbox">
<label>
<input id="tos" name="tos" type="checkbox" required />
利用規約に同意する
</label>
<p id="tosError" class="error" aria-live="polite"></p>
</div>
<button type="submit" id="submitBtn">登録する</button>
<p id="formStatus" class="status" aria-live="polite"></p>
</form>
</body>
</html>
css
body {
font-family: system-ui, sans-serif;
line-height: 1.6;
padding: 24px;
}
.field {
margin-bottom: 16px;
}
label {
display: block;
font-weight: 600;
margin-bottom: 6px;
}
input[type="text"],
input[type="email"],
input[type="number"] {
width: 320px;
max-width: 100%;
padding: 10px;
border: 1px solid #bbb;
border-radius: 6px;
outline: none;
}
input:focus {
border-color: #4b8cf7;
box-shadow: 0 0 0 3px rgba(75, 140, 247, .2);
}
.error {
color: #c83532;
font-size: 12px;
min-height: 1.2em;
margin: 6px 0 0;
}
.is-invalid {
border-color: #c83532 !important;
background: #fff7f7;
}
.checkbox label {
display: inline-flex;
gap: 8px;
align-items: center;
font-weight: 400;
}
button {
padding: 10px 16px;
border: none;
border-radius: 6px;
background: #0ea5e9;
color: #fff;
cursor: pointer;
}
button:disabled {
opacity: .6;
cursor: not-allowed;
}
.status {
margin-top: 12px;
}
JavaScript
// --- デバウンス ---
const debounce = (fn, delay = 200) => {
let t; return (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), delay); };
};
const fields = {
username: { el: document.getElementById("username"), err: document.getElementById("usernameError") },
email: { el: document.getElementById("email"), err: document.getElementById("emailError") },
age: { el: document.getElementById("age"), err: document.getElementById("ageError") },
tos: { el: document.getElementById("tos"), err: document.getElementById("tosError") },
};
// --- ルール ---
const emailPattern = /^[^\s@]+@[^\s@]+\.[a-z]{2,}$/i;
// --- 検証関数 ---
function validateUsername(value) {
if (!value.trim()) return "ユーザー名は必須です";
if (value.trim().length < 3) return "ユーザー名は3文字以上で入力してください";
return "";
}
function validateEmail(value) {
if (!value.trim()) return "メールアドレスは必須です";
if (!emailPattern.test(value.trim())) return "メールアドレスの形式が正しくありません";
return "";
}
function validateAge(value) {
if (value === "" || value === null) return "年齢は必須です";
const n = Number(value);
if (!Number.isFinite(n)) return "年齢は数値で入力してください";
if (n < 0 || n > 120) return "年齢は0〜120の範囲で入力してください";
return "";
}
function validateTos(checked) {
return checked ? "" : "利用規約に同意してください";
}
// --- 表示更新 ---
function renderFieldState(field, message) {
field.err.textContent = message || "";
field.el.classList.toggle("is-invalid", Boolean(message));
}
// --- 単体検証 ---
function validateField(name) {
switch (name) {
case "username":
return renderFieldState(fields.username, validateUsername(fields.username.el.value));
case "email":
return renderFieldState(fields.email, validateEmail(fields.email.el.value));
case "age":
return renderFieldState(fields.age, validateAge(fields.age.el.value));
case "tos":
return renderFieldState(fields.tos, validateTos(fields.tos.el.checked));
}
}
// --- イベント登録 ---
const onInput = debounce((e) => validateField(e.target.id), 180);
["username", "email", "age"].forEach(id => {
fields[id].el.addEventListener("input", onInput);
fields[id].el.addEventListener("blur", (e) => validateField(e.target.id));
});
fields.tos.el.addEventListener("change", () => validateField("tos"));
まとめ
リアルタイムバリデーションは、エラーをその場で直すことができるためユーザビリティの向上につながります。
本記事のテンプレート(HTML/CSS/JS)をベースに、検証ルール・メッセージ・見た目をプロジェクト要件に合わせて調整してみてください。
最後に
JavaScriptの環境構築は、この記事を参照してみてください。
【JavaScript】VSCodeでJavaScriptを使用するための環境構築を実施する – SEもりのLog JavaScript
以上、ログになります。
これからも継続していきましょう!!
コメント