JavaScript

The JavaScript dispatchEvent() method fires an event on an EventTarget, letting you trigger custom or built-in event flows (capture/bubble) in a controlled way for UI, components, and tests.

dispatchEvent

dispatchEvent は「イベントを自分で発火させる」ためのAPIで、伝播(キャプチャ/バブル)と preventDefault() の結果まで含めて制御できます。

このページでできるようになること

まずは直感:dispatchEvent って何?

ざっくり言うと、dispatchEvent は「ユーザーが操作した“ことにする”」ではなく、「イベントという通知をDOMに流す」ためのスイッチです。

正確な定義(仕様に沿った説明)

何のために存在するか

dispatchEvent は、EventTarget(DOM要素、document、window など)に対してイベントを発火し、登録済みのイベントリスナーを呼び出すためのメソッドです。

何に適用されるか(対象)

dispatchEvent は EventTarget を実装するオブジェクトで使えます。典型例は要素(HTMLElement)ですが、document や window、AbortSignal などにもイベント設計の考え方が流用できます。

できること / できないこと(制約)

できること
  • 任意の Event / CustomEvent を発火し、リスナーを順番(キャプチャ→ターゲット→バブル)で実行する
  • cancelable: true のイベントなら preventDefault() によるキャンセルを反映し、戻り値で結果を受け取れる
  • bubbles: true で親要素へ伝播させ、コンポーネント間の通知に使える
できないこと(重要)
  • ユーザー操作と同等の“信頼されたイベント”にすること(event.isTrusted は基本 false)
  • ブラウザが制限している既定動作(例:一部の全画面、クリップボード、ポップアップ)を解除すること
  • 「イベントを投げたら何でも起きる」ようにすること(既定動作はイベント種別・要素・ブラウザ仕様に依存)

影響範囲(レイアウト/描画/ユーザー操作/アクセシビリティ)

レイアウト
dispatchEvent 自体はレイアウトを直接変更しませんが、リスナー内でDOM変更をすれば再計算が起きます(実務では「イベント→DOM更新→再描画」の流れで理解します)。
描画
イベントを発火しただけで描画が変わるのではなく、リスナーがクラス付け替え等をした結果として変わります。
ユーザー操作
ユーザー操作を“再現”する目的に見えても、isTrusted の違いがあり、セキュリティ上の制約が残ります。操作の代用ではなく、通知の設計として使います。
アクセシビリティ
イベントを使ったUIは、キーボード操作(Tab、Enter、Space)やフォーカス移動も含めて成立させます。イベントだけで状態が変わるUIは、状態の可視化(aria-* 等)もセットで確認します。

基本の書き方(最短の型)

最小サンプル(コピペ用)

JavaScript

const target = document.querySelector("#target");

target.addEventListener("ping", (e) => {
    console.log("ping!", e.detail);
});

const ev = new CustomEvent("ping", {
    detail: { from: "dispatchEvent" },
    bubbles: true
});

target.dispatchEvent(ev);

まずは「CustomEvent を作る → dispatchEvent で流す」を覚えるのが最短です。

よく使うオプション/典型パターン

親にも届かせたい
{ bubbles: true }(親要素にバブルする)
キャンセルできる通知にしたい
{ cancelable: true }(リスナーで preventDefault() を許可)
Shadow DOM の外にも出したい
{ composed: true }(影DOM境界を越えられる。設計判断が必要)
データを渡したい
new CustomEvent("name", { detail: ... })

仕様として押さえるポイント(初心者が事故りやすい所)

戻り値は何?(boolean)
dispatchEvent(event) は キャンセルされなかったら true、キャンセルされたら false を返します。キャンセル判定は「cancelable: true のイベントで preventDefault() が呼ばれたか」で決まります。
bubbles が false だと?
ターゲット要素で止まり、親へは届きません。イベント委譲(親でまとめて受ける)の前提が崩れるので、設計として意図が必要です。
cancelable が false だと?
preventDefault() を呼んでも defaultPrevented が立たず、戻り値も変わりません。「止めたつもり」が事故になります。
composed はいつ要る?
Shadow DOM の内外をまたぐ設計で必要になります。外へ出したい通知だけ composed: true にし、むやみに公開範囲を広げないのが安全です。
isTrusted は?
dispatchEvent で作ったイベントは多くの場合 isTrusted: false です。権限が絡む機能(ポップアップ、クリップボード等)はユーザー操作が必須のことがあり、テストと本番を混同しないようにします。
同じ Event を使い回せる?
基本は避けます。イベントオブジェクトは一度の発火で使い切るつもりで、新しく生成して流すのが安全です。

よくある勘違い・混同ポイント

dispatchEvent = ユーザー操作の再現
違います。ユーザー操作は入力デバイス、既定動作、セキュリティ制約まで含みます。dispatchEvent は「イベント通知」を流すだけです。
preventDefault() = 親への伝播を止める
違います。伝播を止めるのは stopPropagation() です。preventDefault() は「既定動作のキャンセル」です(ただし cancelable が必要)。
bubbles: true なら必ず親で受けられる
親側のリスナーが正しい型で登録されている必要があります(キャプチャ/バブル、要素がDOMツリー上にあるか、Shadow DOM境界など)。
「イベント委譲」なら何でも速い
イベントの種類によってはバブルしない/挙動が特殊です。性能は「リスナー数」「発火頻度」「DOM更新の重さ」もセットで見ます(試験対策:計算量というより“定数が効く”系)。

実務でよくある使用例(制作会社の現場を想定)

コンポーネント内部の状態変化を外へ通知する
UI部品の内部で値が変わったとき、CustomEvent で detail に値を載せ、親側が購読する形にします(依存を減らして再利用しやすい)。

JavaScript

function emitChange(el, value) {
    el.dispatchEvent(new CustomEvent("widget:change", {
        detail: { value },
        bubbles: true
    }));
}
フォーム部品のバリデーションを「イベント」で統一する
入力、変更、送信の手前など、検証のタイミングをイベント名で統一すると、実装が散らばりにくいです(ただし既定動作の扱いは慎重に)。
テストで「通知が出るか」を検証する
実ユーザー操作はE2E、通知の有無はユニットテスト、と分けると安定します。dispatchEvent はユニット側で使われがちです。

実務で起きがちな事故と回避策

発火したのに親で受け取れない
  • bubbles が false になっていないか
  • 親のリスナーがキャプチャ(第3引数 true)前提になっていないか
  • ターゲット要素が想定のDOMツリー上にあるか(差し替え/再生成で参照が古いことがある)
DevTools では、発火元要素にブレークポイント(Event Listener Breakpoints)を置くと追いやすいです。
preventDefault() したのに止まらない
  • イベントが cancelable: true か(event.cancelable を確認)
  • 既定動作の“本体”が別の場所にある(例:フォーム送信をコードで呼んでいる)
イベントが二重に走る
  • 同じ要素に複数回 addEventListener していないか(初期化の重複)
  • 親と子の両方で受けていて、バブルで重複したように見えていないか
通知の設計が肥大化する
イベント名・detail の形・公開範囲(bubbles/composed)をルール化し、コンポーネントが勝手に増えないようにします。

アクセシビリティ/UX観点での注意(必要な範囲で)

関連API・関連概念(相互作用)

addEventListener
受け手を登録する。第3引数(または { capture: true })でキャプチャを切り替える。
CustomEvent
detail でデータを渡せる。アプリ独自の通知に向く。
stopPropagation / stopImmediatePropagation
伝播を止める(既定動作は止めない)。
preventDefault
既定動作のキャンセル(cancelable が必要)。
試験対策:イベントループ / タスクキュー
イベントは「発火→リスナー実行」が同期で起きるように見えても、実際には入力やタイマー等でキューに積まれてから処理されます。dispatchEvent は“今その場で”通知を流すので、非同期の前提と混ぜるとバグが出ます。

FE整理(用語・ひっかけ・ミニ問題)

用語

ミニ問題

Q1. dispatchEvent の戻り値が false になる条件は? A. cancelable: true のイベントで、どこかのリスナーが preventDefault() したときです。
Q2. 親でまとめて受けたいのに届きません。最初に疑うべきフラグは? A. bubbles です。false なら親へは届きません。
Q3. preventDefault() と stopPropagation() の違いは? A. preventDefault() は既定動作のキャンセル、stopPropagation() は親への伝播を止めます。
Q4. セキュリティ的に「ユーザー操作が必要」な機能が動きません。なぜ? A. dispatchEvent で作ったイベントは多くの場合 isTrusted が false で、ブラウザが権限系操作を許可しないためです。

FAQ(よくある質問)

Q. dispatchEvent(new Event("click")) と element.click() は同じですか?
A. 同じではありません。dispatchEvent はイベント通知を流すだけで、click() は要素のクリック挙動(仕様に基づく処理)を伴うことがあります。
Q. 戻り値が true / false になるのが分かりません。
A. cancelable: true のときだけ「キャンセルされたか」を見ます。キャンセルされていなければ true、preventDefault() が実行されれば false です。
Q. 親で受けたいのに届きません。
A. bubbles が true か、親のリスナーの登録場所(キャプチャ/バブル)と要素ツリーが想定どおりかを確認します。
Q. 「本番では動くのに、テストで動かない」ことがあります。
A. ユーザー操作由来の isTrusted の違いや、レイアウト計算・フォーカス等の環境差で起きます。通知(dispatchEvent)とUI操作(E2E)を分けて検証します。

症状早見(最短で切り分ける)

症状:親でイベントが取れない
原因候補:bubbles: false / 要素がDOM外 / Shadow DOM境界。確認:ログで event.bubbles と event.composed を見る。
症状:preventDefault() が効かない
原因候補:cancelable: false / 既定動作が別経路。確認:event.cancelable と event.defaultPrevented を見る。
症状:二重に呼ばれる
原因候補:二重登録 / バブルで重複。確認:DevTools の Event Listeners と、どの要素で受けているか。
症状:権限系APIが動かない
原因候補:isTrusted: false でブロック。確認:event.isTrusted とブラウザコンソールの警告。

まとめ:迷ったときの判断軸(短いチェックリスト)