Removes event listener. Must match exact function reference and options used in addEventListener.
All Browsers
dispatchEvent
target.dispatchEvent(event)
Dispatches event to target. Returns false if event is cancelable and any handler called preventDefault().
All Browsers
Option
Type
Description
Default
capture
boolean
If true, listener fires during capture phase before target phase
false
once NEW
boolean
If true, listener automatically removed after first invocation
false
passive NEW
boolean
If true, listener will never call preventDefault(). Improves scroll performance.
false
signal NEW
AbortSignal
AbortSignal to remove listener when signal is aborted. Modern alternative to removeEventListener.
undefined
Example: Event listener registration patterns
// Basic event listenerbutton.addEventListener("click", (event) => { console.log("Button clicked!", event);});// Options object - once optionbutton.addEventListener("click", handleClick, { "once": true });// Automatically removed after first click// Passive listener for scroll performancedocument.addEventListener("scroll", handleScroll, { "passive": true });// Cannot call event.preventDefault()// Capture phaseparent.addEventListener("click", handleCapture, { "capture": true });// Fires before child's event// Remove event listenerconst handler = (e) => console.log(e);button.addEventListener("click", handler);button.removeEventListener("click", handler); // Must use same function reference// AbortController for easy removalconst controller = new AbortController();button.addEventListener("click", handleClick, { "signal": controller.signal });button2.addEventListener("click", handleClick2, { "signal": controller.signal });// Remove all listeners at oncecontroller.abort();
Note: Use passive: true for scroll and touch events to improve performance - browser won't wait for listener to finish before scrolling. The once option is perfect for one-time events like splash screens or initial setup. AbortController provides a clean way to remove multiple listeners.
2. Event Object Properties and Methods
Property/Method
Type
Description
Use Case
type
string
Event type (e.g., "click", "keydown"). Read-only.
Identify event type
target
EventTarget
Element that originated event. Remains same through bubbling. Read-only.
Get original target
currentTarget
EventTarget
Element with listener attached. Changes during bubbling/capture. Read-only.
Get current handler element
eventPhase
number
Current phase: 0=NONE, 1=CAPTURING, 2=AT_TARGET, 3=BUBBLING. Read-only.
Determine event phase
bubbles
boolean
Indicates if event bubbles up DOM tree. Read-only.
Check if event bubbles
cancelable
boolean
Indicates if event can be canceled. Read-only.
Check if cancelable
defaultPrevented
boolean
True if preventDefault() was called. Read-only.
Check if default prevented
timeStamp
number
Time event was created (milliseconds since page load). Read-only.
Measure timing
isTrusted
boolean
True if event initiated by user action, false if created by script. Read-only.
Verify user interaction
preventDefault()
void
Cancels default browser action if event is cancelable. Does nothing if not cancelable.
Prevent default behavior
stopPropagation()
void
Stops event from bubbling/capturing to other elements. Current element's listeners still fire.
Stop event propagation
stopImmediatePropagation()
void
Stops propagation and prevents other listeners on current element from firing.
Stop all propagation
composedPath()
EventTarget[]
Returns array of elements event will/did traverse. Includes shadow DOM elements.
// Prevent default link navigationlink.addEventListener("click", (event) => { event.preventDefault(); console.log("Navigation prevented");});// Stop event bubblingchild.addEventListener("click", (event) => { event.stopPropagation(); console.log("Won't bubble to parent");});// Stop all propagationelement.addEventListener("click", (event) => { event.stopImmediatePropagation(); console.log("No other listeners will fire");});// Check if default was preventedform.addEventListener("submit", (event) => { if (!event.defaultPrevented) { console.log("Form will submit"); }});
Warning:stopPropagation() prevents parent handlers from executing, which can break event delegation patterns. Use with caution. event.target is the original element while event.currentTarget changes during propagation - common source of bugs.
Note: Use CustomEvent instead of Event when you need to pass data - the detail property is the standard way to attach custom data. Always set bubbles: true unless you specifically want to prevent event propagation. For component communication, custom events are cleaner than callbacks.
4. Touch and Pointer Event APIs
Event Type
Description
Fires When
Browser Support
pointerdown
Pointer becomes active (mouse, touch, pen)
Button pressed, screen touched, pen contact
Modern Browsers
pointerup
Pointer becomes inactive
Button released, touch ended, pen lifted
Modern Browsers
pointermove
Pointer position changes
Mouse/touch/pen moves
Modern Browsers
pointercancel
Pointer event canceled by browser
Touch interrupted, too many touches
Modern Browsers
pointerenter
Pointer enters element boundary
Cursor enters, touch starts in element. Doesn't bubble.
Note: Prefer Pointer Events over touch/mouse events - they unify all input types. Use setPointerCapture() to ensure pointer events continue firing even if pointer moves outside element during drag. Set touch-action CSS property to control touch behaviors.
5. Keyboard and Mouse Event Patterns
Event Type
Description
Fires When
Cancelable
keydown
Key pressed down
Key initially pressed. Repeats while held.
Yes
keyup
Key released
Key released after press
Yes
keypress DEPRECATED
Character key pressed (deprecated)
Use keydown instead
Yes
click
Element clicked
Mouse down + up on same element
Yes
dblclick
Element double-clicked
Two clicks in quick succession
Yes
mousedown
Mouse button pressed
Button pressed on element
Yes
mouseup
Mouse button released
Button released
Yes
mousemove
Mouse pointer moved
Pointer moves over element
Yes
mouseenter
Mouse enters element
Pointer enters boundary. Doesn't bubble.
No
mouseleave
Mouse leaves element
Pointer leaves boundary. Doesn't bubble.
No
mouseover
Mouse enters element or child
Pointer enters. Bubbles.
Yes
mouseout
Mouse leaves element or child
Pointer leaves. Bubbles.
Yes
contextmenu
Context menu triggered
Right-click or long-press
Yes
wheel
Mouse wheel scrolled
Wheel rotated over element
Yes
KeyboardEvent Property
Type
Description
Example Values
key
string
Value of key pressed. Preferred modern property.
"a", "Enter", "ArrowLeft"
code
string
Physical key code. Independent of keyboard layout.
"KeyA", "Enter", "ArrowLeft"
keyCode DEPRECATED
number
Numeric key code (deprecated). Use key or code instead.
65, 13, 37
ctrlKey
boolean
True if Ctrl/Command key pressed during event
true / false
shiftKey
boolean
True if Shift key pressed during event
true / false
altKey
boolean
True if Alt/Option key pressed during event
true / false
metaKey
boolean
True if Meta key pressed (Windows/Command key)
true / false
repeat
boolean
True if key held down (auto-repeat)
true / false
MouseEvent Property
Type
Description
Values
button
number
Which button was pressed
0=Left, 1=Middle, 2=Right, 3=Back, 4=Forward
buttons
number
Bitmask of currently pressed buttons
1=Left, 2=Right, 4=Middle (can combine)
clientX / clientY
number
Coordinates relative to viewport
Pixel values
pageX / pageY
number
Coordinates relative to document
Pixel values
screenX / screenY
number
Coordinates relative to screen
Pixel values
offsetX / offsetY
number
Coordinates relative to target element
Pixel values
movementX / movementY
number
Distance moved since last mousemove
Delta in pixels
relatedTarget
Element
Secondary target (for mouseenter/mouseleave)
Element reference
Example: Keyboard event handling
// Modern key detectiondocument.addEventListener("keydown", (event) => { // Use 'key' property (preferred) if (event.key === "Enter") { console.log("Enter pressed"); } // Use 'code' for physical key position if (event.code === "KeyA") { console.log("A key pressed (QWERTY position)"); } // Modifier keys if (event.ctrlKey && event.key === "s") { event.preventDefault(); console.log("Ctrl+S (Save)"); } // Check for key combinations if (event.shiftKey && event.altKey && event.key === "K") { console.log("Shift+Alt+K pressed"); } // Arrow keys switch(event.key) { case "ArrowUp": moveUp(); break; case "ArrowDown": moveDown(); break; case "ArrowLeft": moveLeft(); break; case "ArrowRight": moveRight(); break; } // Prevent auto-repeat if (event.repeat) return;});
Note: Always use event.key instead of deprecated keyCode. Use mouseenter/mouseleave instead of mouseover/mouseout when you don't want events from child elements. For keyboard shortcuts, check modifier keys with ctrlKey, shiftKey, altKey, metaKey.
6. Event Delegation and Event Bubbling
Concept
Description
Benefits
Use Case
Event Bubbling
Events propagate from target element up through ancestors to document root
Enables event delegation. Single listener handles multiple elements.
Default event flow in DOM
Event Capturing
Events propagate from document root down to target element (before bubbling)
Intercept events before target. Use capture: true option.
Special interception needs
Event Delegation
Single listener on parent handles events from multiple children via bubbling
Better performance. Works with dynamic content. Less memory.
Lists, tables, dynamic UI
Event Target
event.target is element that triggered event (child)
Identify actual clicked element in delegation pattern
Determine source element
Current Target
event.currentTarget is element with listener attached (parent)
Reference to delegating element
Access parent in delegation
Event Phase
Value
Description
Direction
NONE
0
Event not being processed
N/A
CAPTURING_PHASE
1
Event traveling from root to target
Top-down
AT_TARGET
2
Event reached target element
At target
BUBBLING_PHASE
3
Event traveling from target to root
Bottom-up
Example: Event delegation pattern
// Instead of attaching listener to each item// ❌ Bad: Many listeners, doesn't work with dynamic contentdocument.querySelectorAll(".item").forEach((item) => { item.addEventListener("click", handleClick);});// ✅ Good: Single listener on parentconst list = document.querySelector("#list");list.addEventListener("click", (event) => { // Check if clicked element matches selector if (event.target.matches(".item")) { console.log("Item clicked:", event.target); handleItem(event.target); } // Or use closest for nested elements const item = event.target.closest(".item"); if (item && list.contains(item)) { console.log("Item found:", item); }});// Works automatically with dynamically added itemsconst newItem = document.createElement("div");newItem.className = "item";list.appendChild(newItem); // Click handler works immediately!
// Multi-action delegationdocument.querySelector("#toolbar").addEventListener("click", (event) => { const button = event.target.closest("button"); if (!button) return; const action = button.dataset.action; switch(action) { case "save": handleSave(); break; case "delete": handleDelete(); break; case "edit": handleEdit(); break; }});// Table row delegationtable.addEventListener("click", (event) => { const row = event.target.closest("tr"); if (!row || row.parentElement.tagName === "THEAD") return; const cell = event.target.closest("td"); const columnIndex = Array.from(row.cells).indexOf(cell); console.log("Row:", row.rowIndex); console.log("Column:", columnIndex); console.log("Data:", row.dataset.id);});// Form delegationform.addEventListener("input", (event) => { const input = event.target; if (input.matches("[data-validate]")) { validateField(input); }});// Performance: Delegate to document for global handlersdocument.addEventListener("click", (event) => { // Close dropdowns when clicking outside if (!event.target.closest(".dropdown")) { closeAllDropdowns(); }});
Note: Event delegation is essential for performance with large lists (hundreds/thousands of items). It automatically handles dynamically added elements without re-attaching listeners. Use event.target.closest(selector) to handle clicks on nested elements within delegated items.
Warning: Not all events bubble! Events like focus, blur, mouseenter, mouseleave don't bubble. Use their bubbling alternatives: focusin, focusout, mouseover, mouseout for delegation. Always check if event.target matches your selector before acting.
Event Handling Best Practices
Use addEventListener with options object for modern features (once, passive, signal)
Prefer Pointer Events over separate mouse/touch handlers for unified input
Use event delegation for lists and dynamic content - better performance and automatic handling of new elements
Set passive: true for scroll/touch events to improve performance
Use event.key instead of deprecated keyCode for keyboard events
Remember: event.target = original element, event.currentTarget = element with listener
Call preventDefault() to stop default browser actions, stopPropagation() to prevent bubbling
Use CustomEvent with detail property for component communication
Clean up listeners with AbortController or removeEventListener to prevent memory leaks