【JavaScript】イベントを無効化する方法|preventDefault・stopPropagation・disabled・removeEventListener・AbortController まで解説

フォームの送信を止めて非同期処理に切り替える、リンクのページ遷移を防ぐ、イベントの親要素への伝播を止めるなど、イベントを無効化する操作は 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 は、ブラウザが本来行うデフォルトの動作をキャンセルします。イベント自体の発火やバブリングは止まりません。

フォーム送信を止めて非同期処理にする

JavaScript
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());
});

リンクのページ遷移を止める

JavaScript
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 は、イベントが親要素に伝播する(バブリング)のを防止します。対象要素でのイベント処理は実行されますが、親のリスナーは発火しなくなります。

JavaScript
const parent = document.getElementById("parent");
const child = document.getElementById("child");

parent.addEventListener("click", () => {
  console.log("親のクリック");
});

child.addEventListener("click", (e) => {
  e.stopPropagation(); // 親に伝播しない
  console.log("子のクリックのみ");
});

// 子をクリック → "子のクリックのみ"(親は発火しない)

実務例: モーダル内のクリックが外のクリックと干渉しないようにする

JavaScript
// オーバーレイクリックでモーダルを閉じる
overlay.addEventListener("click", () => closeModal());

// モーダル内のクリックは閉じ処理を発火させない
modal.addEventListener("click", (e) => {
  e.stopPropagation();
});

stopImmediatePropagation — 同一要素の他リスナーも止める

stopImmediatePropagation は stopPropagation の上位互換で、バブリングを止めるだけでなく、同じ要素に登録されている他のリスナーの実行も止めます。

JavaScript
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 属性を設定すると、ボタンやフォーム要素がグレーアウトされ、クリックやキーボード操作が完全に無効になります。

JavaScript
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 を設定すると、マウス・タッチイベントが要素を貫通し、クリックやホバーが無効になります。

CSS
.disabled-link {
  pointer-events: none;
  opacity: 0.5;
  cursor: default;
}
JavaScript で切り替え
// 無効化
element.style.pointerEvents = "none";

// 有効化
element.style.pointerEvents = "";
pointer-events: none はマウス・タッチイベントのみ無効化します。キーボード操作(Tab → Enter)では依然としてクリックが可能です。完全に無効化するには disabled 属性や tabindex=”-1″ を併用してください。

removeEventListener でリスナーを削除する

JavaScript
function handleClick() {
  console.log("クリック!");
}

const btn = document.getElementById("btn");

// 登録
btn.addEventListener("click", handleClick);

// 削除(同じ関数参照が必要)
btn.removeEventListener("click", handleClick);
匿名関数(アロー関数を直接書く)で登録したリスナーは removeEventListener で削除できません。削除が必要なリスナーは名前付き関数で定義してください。

AbortController でリスナーを一括解除する

ES2022 で addEventListener に signal オプションが追加されました。AbortController を使うと、複数のリスナーを1 回の呼び出しで一括解除できます。

JavaScript
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();
AbortController を使えば、removeEventListener で同じ関数参照を保持する必要がなくなります。SPA のコンポーネント管理に特に有効です。

return false の注意点

jQuery では return falsepreventDefault + stopPropagation の効果を持ちますが、Vanilla JavaScript の addEventListener では return false に意味はありません。

環境 return false の効果
jQuery preventDefault() + stopPropagation()
Vanilla JS(addEventListener) 効果なし
HTML 属性(onclick=”…”) preventDefault() のみ
Vanilla JavaScript では return false に頼らず、明示的に e.preventDefault()e.stopPropagation() を呼んでください。

関連記事

よくある質問

QpreventDefault と stopPropagation はどう使い分けますか?
ApreventDefaultブラウザのデフォルト動作(ページ遷移・フォーム送信など)を止めます。stopPropagationイベントの親要素への伝播を止めます。まったく異なる目的のメソッドなので、必要に応じて片方または両方を使います。
QaddEventListener で登録したリスナーを後から無効化するには?
A名前付き関数で登録し、removeEventListener で同じ関数参照を渡して削除します。または AbortControllersignal オプションを使えば、controller.abort() で一括解除できます。
Qpointer-events: none でキーボード操作も無効になりますか?
Aいいえ。pointer-events: none はマウス・タッチイベントのみ無効化します。Tab キー + Enter でのクリックは有効なままです。完全に無効化するには disabled 属性か tabindex="-1" を併用してください。
QjQuery の return false と同じことを Vanilla JS でやるには?
AjQuery の return falsepreventDefault + stopPropagation の効果があります。Vanilla JS では明示的に e.preventDefault(); e.stopPropagation(); と 2 行書いてください。addEventListener 内の return false には効果がありません。
QAbortController はどのブラウザで使えますか?
AaddEventListener の 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 つのメソッドの影響範囲(デフォルト動作・バブリング・他リスナー)の違いを比較表で確認し、適切に使い分けてください。