JavaScript: Events & Event Handling
Learn how to respond to user interactions using event listeners, the event object, and event propagation.
What Are Events?
An event is something that happens in the browser, such as a user clicking a button, pressing a key, or the page finishing loading. JavaScript lets you react to these events by running code when they occur.
Events
Events are signals fired by the browser when something happens. You can listen for these signals and run a function in response.
- event: an action or occurrence in the browser (click, keypress, load, etc.)
- event handler: a function that runs when a specific event fires
- Events can be triggered by the user or by the browser itself
Common Event Types
A sample of events available in the browser.
Press Run to execute the code and see output here.
Adding Event Listeners
The preferred way to attach a handler is addEventListener(). It accepts the event type, a callback function, and an optional options object.
addEventListener()
Attaches a named or anonymous callback to an element for the specified event type.
- element.addEventListener(type, handler): basic usage
- Multiple listeners of the same type can be added to one element
- Preferred over inline handlers (onclick=) for separation of concerns
addEventListener Example
Attach a click handler to a button.
const btn = document.getElementById("btn");
const msg = document.getElementById("msg");
btn.addEventListener("click", function () {
msg.textContent = "Button was clicked!";
});Removing Event Listeners
Use removeEventListener() to detach a handler. The same function reference must be passed: anonymous functions cannot be removed this way.
removeEventListener()
Removes a previously attached event listener. The handler must be a named function reference, not an anonymous one.
- element.removeEventListener(type, handler): exact function reference required
- Useful for one-time events or cleanup when an element is removed
- Anonymous arrow functions passed inline cannot be removed later
Remove After One Click
The listener removes itself after the first click.
const btn = document.getElementById("btn");
const msg = document.getElementById("msg");
function handleClick() {
msg.textContent = "Clicked! Listener removed.";
btn.removeEventListener("click", handleClick);
}
btn.addEventListener("click", handleClick);Inline Event Handlers
You can set event handlers directly as HTML attributes or DOM properties. These are simpler but limit you to one handler per event per element.
Inline Handlers
Inline handlers are quick but inflexible. They work but are generally discouraged in modern JavaScript.
- onclick attribute: <button onclick="fn()"> in HTML
- DOM property: element.onclick = fn; in JS
- Only one handler per event type: a second assignment overwrites the first
- Prefer addEventListener() which allows multiple handlers
Inline Handler Methods
Two ways to set handlers without addEventListener.
function showAlert() {
document.body.insertAdjacentHTML(
"beforeend",
"<p>HTML inline handler fired!</p>"
);
}
const btn2 = document.getElementById("btn2");
btn2.onclick = function () {
document.body.insertAdjacentHTML(
"beforeend",
"<p>JS property handler fired!</p>"
);
};The Event Object
When an event fires, the browser passes an event object to your handler. It contains details about what happened: which element was clicked, which key was pressed, mouse position, and more.
Event Object (e)
The event object is automatically passed as the first argument to every event handler.
- e.type: the type of event ("click", "keydown", etc.)
- e.target: the element that triggered the event
- e.currentTarget: the element the listener is attached to
- e.timeStamp: when the event occurred (in ms)
Inspecting the Event Object
Read properties from the event object passed to the handler.
const btn = document.getElementById("btn");
const info = document.getElementById("info");
btn.addEventListener("click", function (e) {
info.innerHTML = `
<li>Type: ${e.type}</li>
<li>Target tag: ${e.target.tagName}</li>
<li>TimeStamp: ${Math.round(e.timeStamp)}ms</li>
`;
});preventDefault()
Some events have default browser behaviors: a link navigates, a form submits, right-clicking opens a context menu. Call e.preventDefault() inside your handler to block that default action.
e.preventDefault()
Cancels the browser's built-in behavior for an event while still running your handler code.
- Common use: stop a form from submitting and handle it with JS instead
- Common use: prevent a link from navigating to its href
- Does NOT stop the event from bubbling up the DOM
Prevent Default Navigation
Prevent a link from navigating when clicked.
const link = document.getElementById("link");
const msg = document.getElementById("msg");
link.addEventListener("click", function (e) {
e.preventDefault(); // stop navigation
msg.textContent = "Navigation prevented!";
});stopPropagation()
Events bubble up the DOM by default: clicking a child element also triggers handlers on its parents. Use e.stopPropagation() to stop this bubbling at any point.
e.stopPropagation()
Stops the event from traveling further up (or down) the DOM tree after your handler runs.
- Event bubbling: child fires first, then parent, then grandparent
- Event capturing: parent fires first (third arg true in addEventListener)
- Use stopPropagation() when a child click should not trigger the parent's handler
Stop Propagation Demo
The button click does not bubble to the outer div.
const outer = document.getElementById("outer");
const inner = document.getElementById("inner");
const log = document.getElementById("log");
outer.addEventListener("click", () => {
log.textContent += "Outer clicked. ";
});
inner.addEventListener("click", (e) => {
e.stopPropagation();
log.textContent += "Inner clicked (stopped). ";
});Event Bubbling and Capturing
Events travel through the DOM in two phases: capturing (top-down) and bubbling (bottom-up). By default, listeners fire during the bubbling phase. Pass true as the third argument to listen in the capture phase instead.
Propagation Phases
Understanding event flow helps you control exactly when and where a handler fires.
- Capture phase: event travels from window down to the target
- Target phase: event reaches the element that triggered it
- Bubble phase: event travels back up to window (default listener phase)
- Pass { capture: true } or just true to listen in the capture phase
Bubbling Order
Events fire from the target element upward during the bubble phase.
Press Run to execute the code and see output here.
Event Delegation
Instead of attaching a listener to every child element, attach one listener to the parent and use e.target to identify which child was clicked. This is called event delegation.
Event Delegation
A single parent listener handles events for all current and future children: efficient and works with dynamically added elements.
- Fewer listeners means less memory usage
- Works automatically for elements added to the DOM later
- e.target.matches(selector): check if the clicked element matches a CSS selector
Event Delegation on a List
One listener on the parent handles clicks on all list items.
const list = document.getElementById("list");
const selected = document.getElementById("selected");
list.addEventListener("click", function (e) {
if (e.target.tagName === "LI") {
selected.textContent = "You clicked: " + e.target.textContent;
}
});Mouse Events
Mouse events fire in response to pointer interactions. Common ones include click, dblclick, mouseenter, and mouseleave.
Mouse Events
Mouse events expose extra properties like clientX, clientY (viewport position) and button (which mouse button was pressed).
- click: single click (mousedown + mouseup)
- dblclick: two rapid clicks
- mouseenter / mouseleave: hover in/out, do not bubble
- mouseover / mouseout: similar but do bubble
- e.clientX, e.clientY: cursor position in the viewport
Mouse Events Demo
Track hover and click states on a div.
const box = document.getElementById("box");
const info = document.getElementById("info");
box.addEventListener("mouseenter", () => {
info.textContent = "Mouse entered";
});
box.addEventListener("mouseleave", () => {
info.textContent = "Mouse left";
});
box.addEventListener("click", (e) => {
info.textContent = `Clicked at ${e.clientX}, ${e.clientY}`;
});Keyboard Events
Keyboard events fire when the user presses or releases a key. Use e.key to get a readable key name like "Enter" or "ArrowUp".
Keyboard Events
keydown fires first (repeats while held), keyup fires when released. keypress is deprecated.
- keydown: fires when key is pressed (fires repeatedly if held)
- keyup: fires when key is released
- e.key: human-readable key name ("Enter", "a", "ArrowLeft")
- e.code: physical key code ("KeyA", "Space"), layout-independent
Keyboard Event Demo
Display each key pressed in the input field.
const field = document.getElementById("field");
const output = document.getElementById("output");
field.addEventListener("keydown", function (e) {
output.textContent = `Key: ${e.key} | Code: ${e.code}`;
});Form Events
Forms have their own events for tracking user input and submission. The submit event fires when the form is submitted, and input fires on every keystroke.
Form Events
Handle form events to validate input, update UI live, or send data via fetch instead of a page reload.
- submit: fires when the form is submitted
- input: fires on every value change (live)
- change: fires when focus leaves and value changed
- focus / blur: element gains or loses focus
Form Submit and Input Events
Handle live input and prevent default form submission.
const form = document.getElementById("form");
const nameInput = document.getElementById("name");
const result = document.getElementById("result");
nameInput.addEventListener("input", () => {
result.textContent = "Typing: " + nameInput.value;
});
form.addEventListener("submit", (e) => {
e.preventDefault();
result.textContent = "Submitted: " + nameInput.value;
});Window Events
Window events relate to the page itself: loading, resizing, or scrolling. Attach these listeners to the window object.
Window Events
Window events let you run code when the page finishes loading, the user scrolls, or the browser window is resized.
- load: all resources (images, scripts) have loaded
- DOMContentLoaded: HTML parsed, before images load (faster)
- resize: window dimensions changed
- scroll: user scrolled the page
Window Events
Resize and scroll events attached to the window object.
Press Run to execute the code and see output here.
Custom Events
You can create and dispatch your own events using new CustomEvent(). This is useful for communication between components or modules.
CustomEvent
Custom events let different parts of your code communicate without tight coupling: one part fires an event, another listens for it.
- new CustomEvent(name, { detail }): create with optional data payload
- element.dispatchEvent(event): fire the event
- Listeners use addEventListener with your custom event name
Custom Event Example
Dispatch and listen for a custom event with a data payload.
Press Run to execute the code and see output here.
Knowledge Check
1. Which method is used to attach an event listener to an element?
2. What does e.preventDefault() do?
3. What is event bubbling?
4. What property of the event object refers to the element that triggered the event?
5. What is event delegation?
6. Which method removes an event listener?
7. What does stopPropagation() do?
8. Which event fires when a key is pressed down?