input と change とは何か
input と change は、フォーム要素の値が変わったときに発火するイベントです。input は「値が変わるたびに逐次発火」、change は「確定したタイミングで一度だけ発火」します。ここが重要です:ライブ更新が欲しいなら input、確定後の処理(送信や検証確定)は change。日本語入力(IME)では input が未確定文字を含むため、必要に応じて composition 系イベントと組み合わせて扱います。
基本の違い(逐次 vs 確定)
テキスト入力での挙動
<input id="q" placeholder="検索">
<script>
const q = document.getElementById("q");
q.addEventListener("input", () => console.log("途中:", q.value));
q.addEventListener("change", () => console.log("確定:", q.value));
</script>
HTMLここが重要です:input はキータイプごとに発火しリアルタイム。change はフォーカスが外れる、または Enter・確定操作の後に一度だけ。UI更新の速さが要るなら input、処理確定は change。
select/checkbox/radio での挙動
<select id="sel"><option>りんご</option><option>バナナ</option></select>
<input id="chk" type="checkbox">
<script>
sel.addEventListener("change", () => console.log("選択:", sel.value));
chk.addEventListener("change", () => console.log("チェック:", chk.checked));
</script>
HTMLここが重要です:選択系・チェック系は「操作した瞬間に change」が発火するため、逐次と確定の差は小さく見えます。テキストのような連続入力と区別して考えます。
日本語入力(IME)への対応
composition と組み合わせた安全な判定
<input id="name" placeholder="名前">
<script>
let composing = false;
name.addEventListener("compositionstart", () => composing = true);
name.addEventListener("compositionend", () => { composing = false; onCommit(); });
name.addEventListener("input", () => {
if (!composing) onLive(); // 未確定中は走らせない選択肢
});
function onLive() { console.log("ライブ:", name.value); }
function onCommit() { console.log("確定:", name.value.trim()); }
</script>
HTMLここが重要です:IME中は input が未確定を含みます。厳密な検証や検索実行は compositionend 後、ライブプレビューは composing を避けて走らせると誤動作が減ります。
ライブ更新の設計(input を活かす)
入力に応じてボタンの有効/無効を同期
<input id="email" type="email" required>
<button id="next" disabled>次へ</button>
<script>
const email = document.getElementById("email");
const next = document.getElementById("next");
email.addEventListener("input", () => {
const v = email.value.trim();
next.disabled = !(v && email.validity.valid);
});
</script>
HTMLここが重要です:視覚(文言・ボタン状態)と検証結果を“同じロジック”で同期させると、状態のズレが起きません。validity を活用すると簡潔です。
連続入力の負荷を抑える(デバウンス)
<input id="q" placeholder="検索">
<script>
let timer;
q.addEventListener("input", () => {
clearTimeout(timer);
timer = setTimeout(() => {
console.log("検索:", q.value.trim());
}, 250); // 連続入力の最終のみ実行
});
</script>
HTMLここが重要です:毎キーで重い処理をすると体感が悪化。短い遅延で“入力が止まった”タイミングだけ実行するのが定石です。
確定処理の設計(change を活かす)
設定の保存を確定タイミングで行う
<select id="theme">
<option value="light">明るい</option>
<option value="dark">暗い</option>
</select>
<script>
theme.addEventListener("change", () => {
document.documentElement.dataset.theme = theme.value;
console.log("テーマ保存:", theme.value);
});
</script>
HTMLここが重要です:操作確定時に一度だけ保存・送信・ロギングを行うのは change が適任。無駄な連続処理を避けられます。
ファイル選択の取り扱い
<input id="file" type="file" accept="image/*">
<script>
file.addEventListener("change", () => {
const f = file.files[0];
if (!f) return;
console.log("選択:", f.name, f.size);
});
</script>
HTMLここが重要です:file は change でのみ扱う。input は使えないので、選択確定後に検証・プレビューへ進めます。
よくある落とし穴と回避策
input 乱用で重くなる
毎キーでAPI呼び出しや再描画を走らせるとカクつきます。ここが重要です:デバウンス/スロットルを入れ、軽い UI 更新のみに留め、重い処理は確定(change or compositionend)に寄せます。
Enter で勝手に送信される
フォームの既定動作で Enter が submit になることがあります。ここが重要です:必要なら submit ハンドラで e.preventDefault、または Enter を個別に処理して“意図した送信”だけを許可します。
IME 未考慮のバリデーション誤爆
未確定の途中文字で“無効”判定をしてエラー表示を連発すると不快です。ここが重要です:composing 中は警告を抑える、確定後に厳密判定へ切り替える二段構えにします。
value の前後空白
入力値は trim して判定・送信するのが安全です。ここが重要です:見た目の空白で意図せず無効になるのを防ぎます。
実践例(検索ボックス、価格入力、チェックボックス依存)
検索:ライブ候補+確定検索(IME対応)
<input id="q" placeholder="検索">
<script>
let composing = false, timer;
q.addEventListener("compositionstart", () => composing = true);
q.addEventListener("compositionend", () => { composing = false; runSearch(); });
q.addEventListener("input", () => {
// ライブ候補(composing 中は遅延のみ)
clearTimeout(timer);
timer = setTimeout(() => {
if (!composing) console.log("候補:", q.value);
}, 150);
});
function runSearch() { console.log("確定検索:", q.value.trim()); }
</script>
HTML価格入力:リアルタイム整形と確定保存
<input id="price" inputmode="decimal" placeholder="0">
<script>
price.addEventListener("input", () => {
const num = price.value.replace(/[^\d.]/g, "");
price.value = num; // 入力中は簡易整形
});
price.addEventListener("change", () => {
const v = parseFloat(price.value);
if (Number.isFinite(v)) console.log("保存:", v);
else console.log("数値ではありません");
});
</script>
HTMLここが重要です:入力中は“優しく整える”、確定時に“厳密に検証して保存”。体験と正確さを両立します。
チェックボックスに応じてボタンを有効化
<input id="agree" type="checkbox"> 規約に同意
<button id="next" disabled>次へ</button>
<script>
agree.addEventListener("change", () => {
next.disabled = !agree.checked;
});
</script>
HTMLここが重要です:選択系は change で十分。UI 状態を即同期します。
まとめ
input は“逐次”、change は“確定”。ライブな UI 更新や補助は input に、保存・送信・ロギングなどの確定処理は change に寄せる。日本語入力では compositionstart/end を用いて、未確定中の実行を避け、確定後に厳密処理。負荷の高い処理はデバウンスで間引き、フォーム既定動作と Enter の扱いを明確にする。これらを押さえれば、初心者でも快適で誤動作の少ない入力体験を設計できます。
