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
javascriptelement.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
javascriptconst 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
javascriptelement.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
javascriptelement.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
javascriptform.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
javascriptwindow.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
javascriptelement.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
javascriptbutton.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
javascriptbutton.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
javascriptelement.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
javascriptconst 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
javascriptfunction 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
javascriptfunction 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
javascriptconst modal = document.querySelector('.modal'); document.addEventListener('click', (e) => { if (!modal.contains(e.target)) { closeModal(); } });
Escape Key to Close
javascriptdocument.addEventListener('keydown', (e) => { if (e.key === 'Escape') { closeModal(); } });
React Equivalent
jsxfunction 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: truefor scroll and touch events - Use
once: truefor 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));