addEventListener

The addEventListener() method attaches an event handler to an element without overwriting existing event handlers. It's the modern, recommended way to handle events in JavaScript.

Basic Syntax

javascript
element.addEventListener(event, handler, options);
  • event: String representing the event type (e.g., 'click', 'keydown')
  • handler: Function to execute when event occurs
  • options: Optional object or boolean for advanced configuration

Basic Usage

javascript
const button = document.querySelector('button');

// Basic event listener
button.addEventListener('click', function() {
  console.log('Button clicked!');
});

// Using arrow function
button.addEventListener('click', () => {
  console.log('Button clicked!');
});

// Named function (can be removed later)
function handleClick() {
  console.log('Button clicked!');
}
button.addEventListener('click', handleClick);

Common Events

Mouse Events

javascript
element.addEventListener('click', handler);       // Mouse click
element.addEventListener('dblclick', handler);    // Double click
element.addEventListener('mousedown', handler);   // Mouse button pressed
element.addEventListener('mouseup', handler);     // Mouse button released
element.addEventListener('mousemove', handler);   // Mouse moved
element.addEventListener('mouseenter', handler);  // Mouse enters element
element.addEventListener('mouseleave', handler);  // Mouse leaves element
element.addEventListener('mouseover', handler);   // Mouse over element
element.addEventListener('mouseout', handler);    // Mouse out of element
element.addEventListener('contextmenu', handler); // Right click

Keyboard Events

javascript
element.addEventListener('keydown', handler);     // Key pressed
element.addEventListener('keyup', handler);       // Key released
element.addEventListener('keypress', handler);    // Key pressed (deprecated)

// Example: Enter key detection
input.addEventListener('keydown', (e) => {
  if (e.key === 'Enter') {
    console.log('Enter pressed!');
  }
});

Form Events

javascript
form.addEventListener('submit', handler);         // Form submitted
input.addEventListener('input', handler);         // Input value changed
input.addEventListener('change', handler);        // Input lost focus after change
input.addEventListener('focus', handler);         // Element received focus
input.addEventListener('blur', handler);          // Element lost focus
select.addEventListener('change', handler);       // Select value changed

Window Events

javascript
window.addEventListener('load', handler);         // Page fully loaded
window.addEventListener('DOMContentLoaded', handler); // DOM ready
window.addEventListener('resize', handler);       // Window resized
window.addEventListener('scroll', handler);       // Page scrolled
window.addEventListener('beforeunload', handler); // Before page unload

Other Events

javascript
element.addEventListener('animationend', handler);    // CSS animation ended
element.addEventListener('transitionend', handler);   // CSS transition ended
element.addEventListener('drag', handler);            // Element being dragged
element.addEventListener('drop', handler);            // Element dropped

Event Object

javascript
button.addEventListener('click', (event) => {
  console.log(event.type);           // "click"
  console.log(event.target);         // Element that triggered event
  console.log(event.currentTarget);  // Element with listener attached
  console.log(event.timeStamp);      // When event occurred

  // Mouse events
  console.log(event.clientX);        // X coordinate
  console.log(event.clientY);        // Y coordinate
  console.log(event.button);         // Which button clicked

  // Keyboard events
  console.log(event.key);            // Key value
  console.log(event.code);           // Physical key code
  console.log(event.ctrlKey);        // Ctrl pressed?
  console.log(event.shiftKey);       // Shift pressed?
  console.log(event.altKey);         // Alt pressed?
});

Event Methods

javascript
button.addEventListener('click', (e) => {
  // Prevent default behavior
  e.preventDefault();

  // Stop event propagation
  e.stopPropagation();

  // Stop all other listeners
  e.stopImmediatePropagation();
});

Options Parameter

useCapture (Boolean)

javascript
// Bubble phase (default)
element.addEventListener('click', handler, false);

// Capture phase
element.addEventListener('click', handler, true);

Options Object

javascript
element.addEventListener('click', handler, {
  capture: false,    // Use capture phase
  once: true,        // Remove after first call
  passive: true,     // Never calls preventDefault()
  signal: abortController.signal  // Remove with AbortController
});

Once Option

javascript
// Listener removed automatically after first execution
button.addEventListener('click', () => {
  console.log('Only runs once');
}, { once: true });

Passive Option

javascript
// Improve scroll performance
document.addEventListener('scroll', handler, { passive: true });

// Touch events
element.addEventListener('touchstart', handler, { passive: true });

Removing Event Listeners

Using removeEventListener

javascript
// Must use same function reference
function handleClick() {
  console.log('Clicked');
}

button.addEventListener('click', handleClick);
button.removeEventListener('click', handleClick);

// Won't work (different function instance)
button.addEventListener('click', () => console.log('Click'));
button.removeEventListener('click', () => console.log('Click'));

Using AbortController

javascript
const controller = new AbortController();

button.addEventListener('click', handler, {
  signal: controller.signal
});

// Remove listener
controller.abort();

// Multiple listeners with one controller
const controller2 = new AbortController();

button.addEventListener('click', handler1, { signal: controller2.signal });
button.addEventListener('mouseover', handler2, { signal: controller2.signal });

// Remove all at once
controller2.abort();

Event Delegation

javascript
// Instead of adding listeners to each item
const items = document.querySelectorAll('.item');
items.forEach(item => {
  item.addEventListener('click', handleClick);
});

// Add one listener to parent
const list = document.querySelector('.list');
list.addEventListener('click', (e) => {
  // Check if clicked element is an item
  if (e.target.matches('.item')) {
    handleItemClick(e.target);
  }
});

Common Patterns

Debounce

javascript
function debounce(func, delay) {
  let timeoutId;
  return function(...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, args), delay);
  };
}

// Use with scroll or resize
window.addEventListener('resize', debounce(() => {
  console.log('Resized');
}, 250));

Throttle

javascript
function throttle(func, limit) {
  let inThrottle;
  return function(...args) {
    if (!inThrottle) {
      func.apply(this, args);
      inThrottle = true;
      setTimeout(() => inThrottle = false, limit);
    }
  };
}

// Use with scroll
window.addEventListener('scroll', throttle(() => {
  console.log('Scrolled');
}, 100));

Click Outside

javascript
const modal = document.querySelector('.modal');

document.addEventListener('click', (e) => {
  if (!modal.contains(e.target)) {
    closeModal();
  }
});

Escape Key to Close

javascript
document.addEventListener('keydown', (e) => {
  if (e.key === 'Escape') {
    closeModal();
  }
});

React Equivalent

jsx
function Button() {
  const handleClick = (e) => {
    console.log('Clicked', e);
  };

  return <button onClick={handleClick}>Click me</button>;
}

// With event listener in useEffect
function Component() {
  useEffect(() => {
    const handleResize = () => console.log('Resized');

    window.addEventListener('resize', handleResize);

    // Cleanup
    return () => window.removeEventListener('resize', handleResize);
  }, []);
}

Common Mistakes

Arrow Function vs Regular Function

javascript
// 'this' refers to element with regular function
button.addEventListener('click', function() {
  console.log(this); // button element
});

// 'this' is lexical with arrow function
button.addEventListener('click', () => {
  console.log(this); // outer context, not button
});

Forgetting to Remove Listeners

javascript
// Memory leak
function attachListeners() {
  const button = document.querySelector('button');
  button.addEventListener('click', expensiveHandler);
}

// Call this many times = many listeners
attachListeners();
attachListeners();
attachListeners();

Best Practices

  • Use named functions if you need to remove listeners later
  • Use event delegation for dynamic content
  • Remove event listeners when no longer needed
  • Use passive: true for scroll and touch events
  • Use once: true for one-time events
  • Debounce/throttle expensive handlers
  • Avoid inline event handlers in HTML
  • Consider using AbortController for cleanup

Performance Tips

javascript
// Good: Event delegation
parent.addEventListener('click', (e) => {
  if (e.target.matches('.item')) {
    handleClick(e.target);
  }
});

// Avoid: Many individual listeners
items.forEach(item => {
  item.addEventListener('click', handleClick);
});

// Good: Passive scrolling
window.addEventListener('scroll', handler, { passive: true });

// Good: Debounce expensive operations
window.addEventListener('resize', debounce(expensiveOperation, 200));

Learn More