フォームの送信を止めて非同期処理に切り替える、リンクのページ遷移を防ぐ、イベントの親要素への伝播を止めるなど、イベントを無効化する操作は JavaScript 開発で必須のテクニックです。この記事では「何を止めるのか」に応じた正しいメソッドの選び方を整理します。
・preventDefault でデフォルト動作を止める方法
・stopPropagation でバブリングを止める方法
・stopImmediatePropagation で同一要素の他リスナーも止める方法
・disabled 属性で UI 的にボタンを無効化する方法
・CSS pointer-events: none でクリックを無効化する方法
・removeEventListener でリスナーを削除する方法
・AbortController でリスナーを一括解除する方法
イベント無効化メソッドの使い分け早見表
| やりたいこと | 使うメソッド / 手法 |
|---|---|
| デフォルト動作(ページ遷移・フォーム送信)を止める | event.preventDefault() |
| 親要素へのイベント伝播を止める | event.stopPropagation() |
| 同じ要素の他リスナーも含めて全て止める | event.stopImmediatePropagation() |
| ボタンをクリック不可にする | element.disabled = true |
| 要素のクリックを CSS で無効化する | pointer-events: none |
| 登録済みリスナーを削除する | removeEventListener() |
| 複数リスナーを一括解除する | AbortController |
preventDefault — デフォルト動作を止める
preventDefault は、ブラウザが本来行うデフォルトの動作をキャンセルします。イベント自体の発火やバブリングは止まりません。
フォーム送信を止めて非同期処理にする
const form = document.getElementById("myForm");
form.addEventListener("submit", async (e) => {
e.preventDefault(); // ページリロードを防止
const formData = new FormData(form);
const res = await fetch("/api/submit", {
method: "POST",
body: formData
});
console.log("送信完了:", await res.json());
});
リンクのページ遷移を止める
document.querySelectorAll("a.no-navigate").forEach(link => {
link.addEventListener("click", (e) => {
e.preventDefault();
console.log("遷移せず、独自処理を実行");
});
});
よくある preventDefault の対象
| イベント | デフォルト動作 | 止める理由 |
|---|---|---|
submit |
フォーム送信(ページリロード) | Ajax / fetch で非同期送信に変更 |
click(a タグ) |
ページ遷移 | SPA のルーティング、独自処理 |
contextmenu |
右クリックメニュー表示 | カスタムメニューを表示 |
keydown |
キー入力のデフォルト動作 | 特定キーの動作を変更 |
wheel |
スクロール | カスタムスクロール処理 |
preventDefault はデフォルト動作を止めるだけで、イベントの伝播(バブリング)は止まりません。バブリングも止めたい場合は stopPropagation を併用してください。stopPropagation — バブリング(伝播)を止める
stopPropagation は、イベントが親要素に伝播する(バブリング)のを防止します。対象要素でのイベント処理は実行されますが、親のリスナーは発火しなくなります。
const parent = document.getElementById("parent");
const child = document.getElementById("child");
parent.addEventListener("click", () => {
console.log("親のクリック");
});
child.addEventListener("click", (e) => {
e.stopPropagation(); // 親に伝播しない
console.log("子のクリックのみ");
});
// 子をクリック → "子のクリックのみ"(親は発火しない)
実務例: モーダル内のクリックが外のクリックと干渉しないようにする
// オーバーレイクリックでモーダルを閉じる
overlay.addEventListener("click", () => closeModal());
// モーダル内のクリックは閉じ処理を発火させない
modal.addEventListener("click", (e) => {
e.stopPropagation();
});
stopImmediatePropagation — 同一要素の他リスナーも止める
stopImmediatePropagation は stopPropagation の上位互換で、バブリングを止めるだけでなく、同じ要素に登録されている他のリスナーの実行も止めます。
const btn = document.getElementById("btn");
btn.addEventListener("click", (e) => {
console.log("リスナー1: 実行される");
e.stopImmediatePropagation();
});
btn.addEventListener("click", () => {
console.log("リスナー2: 実行されない");
});
// ボタンをクリック → "リスナー1: 実行される" のみ
| メソッド | デフォルト動作 | バブリング | 同一要素の他リスナー |
|---|---|---|---|
preventDefault() |
止める | 止めない | 止めない |
stopPropagation() |
止めない | 止める | 止めない |
stopImmediatePropagation() |
止めない | 止める | 止める |
stopImmediatePropagation はリスナーの登録順序に依存します。先に登録されたリスナーで呼ぶと後のリスナーが止まりますが、後のリスナーで呼んでも先のリスナーは既に実行済みです。disabled 属性で UI 的に無効化する
disabled 属性を設定すると、ボタンやフォーム要素がグレーアウトされ、クリックやキーボード操作が完全に無効になります。
const btn = document.getElementById("submitBtn");
// 無効化
btn.disabled = true;
// 有効化
btn.disabled = false;
const btn = document.getElementById("submitBtn");
btn.addEventListener("click", async () => {
btn.disabled = true;
btn.textContent = "送信中...";
try {
await fetch("/api/submit", { method: "POST" });
btn.textContent = "送信完了";
} catch (e) {
btn.disabled = false;
btn.textContent = "再送信";
}
});
disabled はフォーム要素(button, input, select, textarea)でのみ使えます。div や span には効きません。CSS pointer-events: none でクリックを無効化する
CSS の pointer-events: none を設定すると、マウス・タッチイベントが要素を貫通し、クリックやホバーが無効になります。
.disabled-link {
pointer-events: none;
opacity: 0.5;
cursor: default;
}
// 無効化 element.style.pointerEvents = "none"; // 有効化 element.style.pointerEvents = "";
pointer-events: none はマウス・タッチイベントのみ無効化します。キーボード操作(Tab → Enter)では依然としてクリックが可能です。完全に無効化するには disabled 属性や tabindex=”-1″ を併用してください。removeEventListener でリスナーを削除する
function handleClick() {
console.log("クリック!");
}
const btn = document.getElementById("btn");
// 登録
btn.addEventListener("click", handleClick);
// 削除(同じ関数参照が必要)
btn.removeEventListener("click", handleClick);
AbortController でリスナーを一括解除する
ES2022 で addEventListener に signal オプションが追加されました。AbortController を使うと、複数のリスナーを1 回の呼び出しで一括解除できます。
const controller = new AbortController();
const { signal } = controller;
// signal を渡してリスナーを登録
document.addEventListener("click", () => console.log("click"), { signal });
document.addEventListener("keydown", () => console.log("keydown"), { signal });
window.addEventListener("scroll", () => console.log("scroll"), { signal });
// すべてのリスナーを一括解除
controller.abort();
// → click, keydown, scroll のリスナーがすべて削除される
function initComponent(element) {
const controller = new AbortController();
const { signal } = controller;
element.addEventListener("click", handleClick, { signal });
element.addEventListener("mouseenter", handleHover, { signal });
window.addEventListener("resize", handleResize, { signal });
// クリーンアップ関数を返す
return () => controller.abort();
}
const cleanup = initComponent(myElement);
// 不要になったら一括解除
cleanup();
return false の注意点
jQuery では return false が preventDefault + stopPropagation の効果を持ちますが、Vanilla JavaScript の addEventListener では return false に意味はありません。
| 環境 | return false の効果 |
|---|---|
| jQuery | preventDefault() + stopPropagation() |
| Vanilla JS(addEventListener) | 効果なし |
| HTML 属性(onclick=”…”) | preventDefault() のみ |
return false に頼らず、明示的に e.preventDefault() と e.stopPropagation() を呼んでください。関連記事
- クリックイベントの設定方法 — addEventListener・バブリング・イベント委任
- 送信ボタンの連続クリックを防ぐテクニック
- マウスイベントの使い方
- フォーカスイベントの使い方
- Event Delegation で効率的にイベントを管理する方法
- 右クリックを禁止する方法
よくある質問
preventDefault はブラウザのデフォルト動作(ページ遷移・フォーム送信など)を止めます。stopPropagation はイベントの親要素への伝播を止めます。まったく異なる目的のメソッドなので、必要に応じて片方または両方を使います。removeEventListener で同じ関数参照を渡して削除します。または AbortController の signal オプションを使えば、controller.abort() で一括解除できます。pointer-events: none はマウス・タッチイベントのみ無効化します。Tab キー + Enter でのクリックは有効なままです。完全に無効化するには disabled 属性か tabindex="-1" を併用してください。return false は preventDefault + stopPropagation の効果があります。Vanilla JS では明示的に e.preventDefault(); e.stopPropagation(); と 2 行書いてください。addEventListener 内の return false には効果がありません。signal オプションは ES2022 で策定され、Chrome 90+ / Firefox 88+ / Safari 15+ で対応しています。IE は非対応ですが、モダンブラウザでは問題なく使えます。まとめ
JavaScript でイベントを無効化する方法を整理しました。
- デフォルト動作を止める:
e.preventDefault() - バブリングを止める:
e.stopPropagation() - 同一要素の他リスナーも止める:
e.stopImmediatePropagation() - ボタンを無効化:
disabled = true(フォーム要素限定) - CSS でクリック無効化:
pointer-events: none(キーボード操作は止まらない) - リスナーの削除:
removeEventListenerまたはAbortController
「何を止めたいのか」を明確にし、正しいメソッドを選ぶことが重要です。3 つのメソッドの影響範囲(デフォルト動作・バブリング・他リスナー)の違いを比較表で確認し、適切に使い分けてください。