Interactivity is the heart of a web application. How does JavaScript "listen" for when a user clicks a button, types in a form, or scrolls the page? The answer is the Event Listener. With addEventListener(), we can specify what code should run when an event occurs on an element.
The Basics of Using addEventListener
The basic syntax is element.addEventListener(eventName, handlerFunction):
const button = document.getElementById('btn-click');
// Method 1: Inline function (anonymous function)
button.addEventListener('click', function() {
console.log('Button clicked!');
});
// Method 2: Arrow function (more concise)
button.addEventListener('click', () => {
alert('Hello from the button!');
});
// Method 3: Separate function (easier to remove later)
function handleClick() {
console.log('The separate handler function was called.');
}
button.addEventListener('click', handleClick);
// Removing an event listener (must use the same function reference)
button.removeEventListener('click', handleClick);
The Event Object
Every event listener receives an event object as its first parameter. This object contains useful information about the event that occurred:
const box = document.getElementById('box');
box.addEventListener('click', function(event) {
console.log('Clicked element:', event.target); // the specific element that was clicked
console.log('Event type:', event.type); // 'click'
console.log('Mouse X position:', event.clientX);
console.log('Mouse Y position:', event.clientY);
// Prevent the default behavior (e.g. prevent a link from navigating)
event.preventDefault();
// Stop the event from "bubbling up" to the parent element
event.stopPropagation();
});
Keyboard Events
Detecting keyboard key presses is very useful for creating shortcuts or real-time validation:
const searchInput = document.getElementById('search-input');
// keydown — when a key is pressed
// keyup — when a key is released
// keypress — deprecated, avoid using it
searchInput.addEventListener('keydown', function(e) {
console.log('Key pressed:', e.key); // key name: 'Enter', 'a', 'Backspace', etc.
console.log('Key code:', e.code); // 'Enter', 'KeyA', 'Backspace'
if (e.key === 'Enter') {
console.log('Searching:', this.value);
// perform the search...
}
// Check for the Ctrl + S combination
if (e.ctrlKey && e.key === 's') {
e.preventDefault(); // Prevent the browser's save dialog
console.log('Saving...');
}
});
Events on Forms and Inputs
const form = document.getElementById('my-form');
const nameInput = document.getElementById('name-input');
// change — when the value changes and the element loses focus
nameInput.addEventListener('change', (e) => {
console.log('Value changed to:', e.target.value);
});
// input — when the value changes in real time (every character)
nameInput.addEventListener('input', (e) => {
const charCount = e.target.value.length;
document.getElementById('counter').textContent = `${charCount}/100 characters`;
});
// focus & blur
nameInput.addEventListener('focus', () => {
nameInput.style.borderColor = 'blue';
});
nameInput.addEventListener('blur', () => {
nameInput.style.borderColor = '';
});
// form submit
form.addEventListener('submit', (e) => {
e.preventDefault(); // Prevent the page from reloading
console.log('Form submitted!');
});
Event Delegation
Instead of adding an event listener to every element one by one (which is inefficient), we can take advantage of event delegation — attach a single listener to the parent element and use event.target to determine which element was clicked:
const list = document.getElementById('item-list');
// A single listener for all items and the delete buttons inside them
list.addEventListener('click', function(e) {
// Check whether a delete button was clicked
if (e.target.classList.contains('btn-delete')) {
const item = e.target.closest('li'); // Find the nearest <li> element
item.remove();
console.log('Item removed!');
}
// Check whether the item text was clicked
if (e.target.tagName === 'SPAN') {
e.target.classList.toggle('done');
}
});
// The advantage: this listener automatically works for newly added items!
function addItem(text) {
list.insertAdjacentHTML('beforeend', `
<li>
<span>${text}</span>
<button class="btn-delete">Delete</button>
</li>
`);
}
Scroll and Resize Events
// scroll event — when the user scrolls the page
window.addEventListener('scroll', function() {
const scrollPosition = window.scrollY;
// Show the "back to top" button once scrolled more than 300px
const backToTopBtn = document.getElementById('btn-top');
if (scrollPosition > 300) {
backToTopBtn.style.display = 'block';
} else {
backToTopBtn.style.display = 'none';
}
});
// resize event — when the window size changes
window.addEventListener('resize', function() {
console.log('Window width:', window.innerWidth);
console.log('Window height:', window.innerHeight);
});
Commonly Used Events
- click — a mouse click on an element
- dblclick — a double click
- mouseover / mouseout — the cursor enters/leaves the element's area
- keydown / keyup — a keyboard key is pressed/released
- input / change — an input value changes
- submit — a form is submitted
- focus / blur — an element gains/loses focus
- load — a page or resource finishes loading
- DOMContentLoaded — the DOM has finished parsing
- scroll — the page is scrolled
Conclusion
Event Listeners are the foundation of web interactivity. By understanding how addEventListener() works, using the event object, applying event delegation for efficiency, and knowing the various types of events available, you already have the tools to build responsive and interactive interfaces. Always choose event delegation when handling dynamic elements or long lists for optimal performance.