Events are the foundation of interactive web pages. Every time a user clicks a button, types in an input, submits a form, or moves their mouse, an event occurs. JavaScript's event system allows you to listen for these events and respond with custom behavior. The addEventListener() method is your gateway to creating rich, interactive user experiences. Let's master event handling!
What Are Events?
Events are actions or occurrences that happen in the browser. They can be triggered by users or by the browser itself.
Common Event Categories:
- Mouse Events: click, dblclick, mousedown, mouseup, mousemove, mouseenter, mouseleave
- Keyboard Events: keydown, keyup, keypress
- Form Events: submit, input, change, focus, blur
- Document Events: DOMContentLoaded, load, scroll, resize
- Drag Events: drag, dragstart, dragend, drop
<!DOCTYPE html>
<html>
<body>
<button id="btn">Click Me</button>
<script>
// Event happens when button is clicked
// JavaScript can "listen" for this event and respond
let button = document.getElementById('btn');
// This is an event listener
button.addEventListener('click', function() {
console.log('Button was clicked!');
});
// User clicks button → 'click' event fires → our function runs
</script>
</body>
</html>addEventListener() - The Modern Way
The addEventListener() method is the recommended way to handle events in modern JavaScript.
Basic Syntax
// Syntax: element.addEventListener(eventType, handlerFunction)
let button = document.getElementById('btn');
// Method 1: Anonymous function
button.addEventListener('click', function() {
console.log('Button clicked!');
});
// Method 2: Named function
function handleClick() {
console.log('Button clicked!');
}
button.addEventListener('click', handleClick);
// Method 3: Arrow function
button.addEventListener('click', () => {
console.log('Button clicked!');
});Multiple Listeners on Same Element
let button = document.getElementById('btn');
// You can add multiple listeners for the same event!
button.addEventListener('click', function() {
console.log('First listener');
});
button.addEventListener('click', function() {
console.log('Second listener');
});
button.addEventListener('click', function() {
console.log('Third listener');
});
// When button is clicked, ALL three functions run:
// Output:
// First listener
// Second listener
// Third listenerWhy addEventListener() is Better
addEventListener is more flexible
Old Way (onclick)
// Old way: onclick property
let button = document.getElementById('btn');
// Only ONE function can be assigned
button.onclick = function() {
console.log('First function');
};
// This REPLACES the previous function!
button.onclick = function() {
console.log('Second function');
};
// Only "Second function" will run
// Mixing HTML and JavaScript
// <button onclick="handleClick()">Click</button>
// ↑ Not recommended (inline event handlers)Modern Way (addEventListener)
// Modern way: addEventListener
let button = document.getElementById('btn');
// Multiple functions can listen
button.addEventListener('click', function() {
console.log('First function');
});
button.addEventListener('click', function() {
console.log('Second function');
});
// BOTH functions run!
// Clean separation of HTML and JavaScript
// Good for maintainabilityCommon Event Types
Mouse Events
<!DOCTYPE html>
<html>
<body>
<button id="btn">Hover and Click</button>
<div id="output"></div>
<script>
let button = document.getElementById('btn');
let output = document.getElementById('output');
// click - mouse button pressed and released
button.addEventListener('click', function() {
output.textContent = 'Button clicked!';
});
// dblclick - double click
button.addEventListener('dblclick', function() {
output.textContent = 'Button double-clicked!';
});
// mouseenter - mouse enters element area
button.addEventListener('mouseenter', function() {
output.textContent = 'Mouse entered button';
button.style.backgroundColor = 'lightblue';
});
// mouseleave - mouse leaves element area
button.addEventListener('mouseleave', function() {
output.textContent = 'Mouse left button';
button.style.backgroundColor = '';
});
// mousedown - mouse button pressed (not released yet)
button.addEventListener('mousedown', function() {
output.textContent = 'Mouse button down';
});
// mouseup - mouse button released
button.addEventListener('mouseup', function() {
output.textContent = 'Mouse button up';
});
</script>
</body>
</html>Keyboard Events
<!DOCTYPE html>
<html>
<body>
<input type="text" id="textbox" placeholder="Type here">
<div id="output"></div>
<script>
let textbox = document.getElementById('textbox');
let output = document.getElementById('output');
// keydown - key is pressed down
textbox.addEventListener('keydown', function(event) {
output.textContent = `Key down: ${event.key}`;
});
// keyup - key is released
textbox.addEventListener('keyup', function(event) {
output.textContent = `Key up: ${event.key}`;
});
// keypress - key is pressed (deprecated, use keydown instead)
// Specific key detection
textbox.addEventListener('keydown', function(event) {
if (event.key === 'Enter') {
console.log('Enter key pressed!');
}
if (event.key === 'Escape') {
console.log('Escape key pressed!');
textbox.value = '';
}
// Check for Ctrl/Cmd + S (save)
if ((event.ctrlKey || event.metaKey) && event.key === 's') {
event.preventDefault(); // Prevent browser save dialog
console.log('Save shortcut pressed!');
}
});
</script>
</body>
</html>Form Events
<!DOCTYPE html>
<html>
<body>
<form id="myForm">
<input type="text" id="username" placeholder="Username">
<input type="email" id="email" placeholder="Email">
<button type="submit">Submit</button>
</form>
<script>
let form = document.getElementById('myForm');
let username = document.getElementById('username');
let email = document.getElementById('email');
// submit - form is submitted
form.addEventListener('submit', function(event) {
event.preventDefault(); // Prevent page reload
console.log('Form submitted!');
console.log('Username:', username.value);
console.log('Email:', email.value);
});
// input - input value changes (every keystroke)
username.addEventListener('input', function(event) {
console.log('Current value:', event.target.value);
});
// change - input loses focus after value changed
email.addEventListener('change', function(event) {
console.log('Email changed to:', event.target.value);
});
// focus - element receives focus
username.addEventListener('focus', function() {
console.log('Username input focused');
this.style.backgroundColor = 'lightyellow';
});
// blur - element loses focus
username.addEventListener('blur', function() {
console.log('Username input blurred');
this.style.backgroundColor = '';
});
</script>
</body>
</html>Document/Window Events
// DOMContentLoaded - HTML is fully loaded and parsed
document.addEventListener('DOMContentLoaded', function() {
console.log('DOM is ready!');
// Safe to access all DOM elements now
});
// load - entire page loaded (images, styles, scripts)
window.addEventListener('load', function() {
console.log('Everything loaded!');
});
// scroll - page or element is scrolled
window.addEventListener('scroll', function() {
console.log('Page scrolled to:', window.scrollY);
});
// resize - window is resized
window.addEventListener('resize', function() {
console.log('Window size:', window.innerWidth, 'x', window.innerHeight);
});
// beforeunload - user is leaving page
window.addEventListener('beforeunload', function(event) {
// Show confirmation dialog
event.preventDefault();
event.returnValue = '';
});The 'this' Keyword in Event Handlers
Inside an event handler, this refers to the element that the listener is attached to.
<!DOCTYPE html>
<html>
<body>
<button class="btn" id="btn1">Button 1</button>
<button class="btn" id="btn2">Button 2</button>
<button class="btn" id="btn3">Button 3</button>
<script>
let buttons = document.querySelectorAll('.btn');
buttons.forEach(button => {
// Regular function - 'this' is the button
button.addEventListener('click', function() {
console.log('Clicked:', this.id);
this.style.backgroundColor = 'blue';
this.style.color = 'white';
});
});
// Arrow function - 'this' is NOT the button!
let btn1 = document.getElementById('btn1');
btn1.addEventListener('click', () => {
// 'this' here refers to the surrounding context (window)
console.log(this); // Window object, not the button!
});
// Use event.target or event.currentTarget instead
btn1.addEventListener('click', (event) => {
console.log('Clicked:', event.currentTarget.id);
event.currentTarget.style.backgroundColor = 'red';
});
</script>
</body>
</html>Arrow Functions and 'this': Arrow functions don't have their own this. Use regular functions for event handlers if you need this to refer to the element, or use event.currentTarget in arrow functions.
Removing Event Listeners
Use removeEventListener() to remove event listeners. You must pass the same function reference.
<!DOCTYPE html>
<html>
<body>
<button id="btn">Click Me</button>
<button id="remove">Remove Listener</button>
<script>
let button = document.getElementById('btn');
let removeBtn = document.getElementById('remove');
// Named function (can be removed)
function handleClick() {
console.log('Button clicked!');
}
// Add listener
button.addEventListener('click', handleClick);
// Remove listener (same function reference!)
removeBtn.addEventListener('click', function() {
button.removeEventListener('click', handleClick);
console.log('Listener removed');
});
// Anonymous functions CAN'T be removed!
button.addEventListener('click', function() {
console.log('This listener cannot be removed');
});
// This won't work (different function reference)
button.removeEventListener('click', function() {
console.log('Button clicked!');
});
</script>
</body>
</html>One-Time Event Listeners
let button = document.getElementById('btn');
// Method 1: Manual removal
function handleClick() {
console.log('Clicked once!');
button.removeEventListener('click', handleClick);
}
button.addEventListener('click', handleClick);
// Method 2: Use 'once' option (modern)
button.addEventListener('click', function() {
console.log('This will only run once!');
}, { once: true });
// The listener automatically removes itself after first triggerEvent Listener Options
let element = document.getElementById('element');
// addEventListener accepts a third parameter (options object)
// once: automatically remove after first trigger
element.addEventListener('click', handler, { once: true });
// passive: improve scroll performance (can't preventDefault)
element.addEventListener('scroll', handler, { passive: true });
// capture: use capturing phase instead of bubbling (covered in next lesson)
element.addEventListener('click', handler, { capture: true });
// Combine options
element.addEventListener('click', handler, {
once: true,
passive: true,
capture: false
});Practical Examples
Example 1: Interactive Counter
<!DOCTYPE html>
<html>
<head>
<style>
.counter {
font-size: 48px;
text-align: center;
margin: 20px;
}
button {
font-size: 20px;
padding: 10px 20px;
margin: 5px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="counter" id="count">0</div>
<div style="text-align: center;">
<button id="increment">+</button>
<button id="decrement">-</button>
<button id="reset">Reset</button>
</div>
<script>
let count = 0;
let display = document.getElementById('count');
let incrementBtn = document.getElementById('increment');
let decrementBtn = document.getElementById('decrement');
let resetBtn = document.getElementById('reset');
function updateDisplay() {
display.textContent = count;
// Change color based on value
if (count > 0) {
display.style.color = 'green';
} else if (count < 0) {
display.style.color = 'red';
} else {
display.style.color = 'black';
}
}
incrementBtn.addEventListener('click', function() {
count++;
updateDisplay();
});
decrementBtn.addEventListener('click', function() {
count--;
updateDisplay();
});
resetBtn.addEventListener('click', function() {
count = 0;
updateDisplay();
});
// Keyboard shortcuts
document.addEventListener('keydown', function(event) {
if (event.key === 'ArrowUp') {
count++;
updateDisplay();
} else if (event.key === 'ArrowDown') {
count--;
updateDisplay();
} else if (event.key === 'r') {
count = 0;
updateDisplay();
}
});
</script>
</body>
</html>Example 2: Form Validation
<!DOCTYPE html>
<html>
<head>
<style>
.error { border: 2px solid red; }
.valid { border: 2px solid green; }
.error-message { color: red; font-size: 12px; }
</style>
</head>
<body>
<form id="registrationForm">
<div>
<input type="text" id="username" placeholder="Username (min 3 chars)">
<div id="usernameError" class="error-message"></div>
</div>
<div>
<input type="email" id="email" placeholder="Email">
<div id="emailError" class="error-message"></div>
</div>
<div>
<input type="password" id="password" placeholder="Password (min 6 chars)">
<div id="passwordError" class="error-message"></div>
</div>
<button type="submit">Register</button>
</form>
<script>
let form = document.getElementById('registrationForm');
let username = document.getElementById('username');
let email = document.getElementById('email');
let password = document.getElementById('password');
// Real-time validation
username.addEventListener('input', function() {
let error = document.getElementById('usernameError');
if (this.value.length < 3) {
this.classList.remove('valid');
this.classList.add('error');
error.textContent = 'Username must be at least 3 characters';
} else {
this.classList.remove('error');
this.classList.add('valid');
error.textContent = '';
}
});
email.addEventListener('input', function() {
let error = document.getElementById('emailError');
if (!this.value.includes('@')) {
this.classList.remove('valid');
this.classList.add('error');
error.textContent = 'Please enter a valid email';
} else {
this.classList.remove('error');
this.classList.add('valid');
error.textContent = '';
}
});
password.addEventListener('input', function() {
let error = document.getElementById('passwordError');
if (this.value.length < 6) {
this.classList.remove('valid');
this.classList.add('error');
error.textContent = 'Password must be at least 6 characters';
} else {
this.classList.remove('error');
this.classList.add('valid');
error.textContent = '';
}
});
// Form submission
form.addEventListener('submit', function(event) {
event.preventDefault();
let isValid = username.classList.contains('valid') &&
email.classList.contains('valid') &&
password.classList.contains('valid');
if (isValid) {
console.log('Form submitted successfully!');
console.log({
username: username.value,
email: email.value,
password: password.value
});
} else {
alert('Please fix all errors before submitting');
}
});
</script>
</body>
</html>Event Handling Practice
Master event listeners and user interactions
console.log() to see your output in the console above.Key Takeaways
- Events are actions that happen in the browser (clicks, keypresses, etc.)
addEventListener()is the modern way to handle events- Multiple listeners can be attached to the same element
- Syntax:
element.addEventListener('eventType', handler) - Common events: click, input, submit, keydown, mouseenter, scroll
thisin regular functions refers to the element- Arrow functions don't have their own
this removeEventListener()needs same function reference- Use
{ once: true }for one-time listeners event.preventDefault()stops default behavior
What's Next?
You now know how to handle events and respond to user interactions! You've learned addEventListener(), common event types, and how to build interactive features like counters and form validation.
In the final DOM manipulation lesson, we'll explore the Event Object and Event Delegation—learning about the event object that's passed to handlers, event bubbling and capturing, and the powerful event delegation pattern that makes dynamic content efficient!
💪 Practice Challenge:
Before moving on, try creating:
- A button that changes color when clicked
- An input that displays character count as you type
- A form with real-time validation feedback
- A counter with keyboard shortcuts (arrow keys)
- A button that can only be clicked once