Events
Understand what a DOM event is, survey the major categories of events (mouse, keyboard, form, focus, and page-lifecycle events), and know when each one fires.
Almost everything interactive on a web page — a button reacting to a click, a form warning you about a missing field, a page waiting until images have loaded before running a script — is built on events. An event is a signal the browser sends out when something happens: the user clicks, types, scrolls, submits a form, or even just when the page itself finishes loading. JavaScript's job is to listen for these signals and run code in response.
What is an event?
An event is an object the browser creates and dispatches to a specific target (usually a DOM element, but also window or document) whenever something noteworthy happens: a mouse click, a key press, a network response finishing, a CSS transition ending, and hundreds of other occurrences all have corresponding event types.
Events are not something you have to build yourself — the browser fires them automatically as part of its normal operation. Your job as a developer is to attach a listener (a function) to the element and event type you care about, and the browser will call that function whenever the event occurs, passing it an event object describing exactly what happened.
Mouse and pointer events
Mouse events fire in response to a physical mouse (or, in practice, to touch input the browser translates into mouse-like behavior). The most common is click, which fires after a full press-and-release on the same element. Related but more granular events let you track the press and release separately.
Pointer events (pointerdown, pointerup, pointermove, pointerenter, pointerleave, and so on) were introduced to unify mouse, touch, and stylus/pen input under a single event model, since a modern site has to support all three. Where you need input-device-agnostic behavior — a custom drag-and-drop widget, for example — pointer events are usually the better choice over mouse-only events.
• click — fires after a complete press-and-release of the primary mouse button (or a tap) on the same element • dblclick — fires on a rapid double click • mousedown / mouseup — the press and release, fired separately, useful for drag interactions • mousemove — fires continuously as the pointer moves over an element • mouseenter / mouseleave — fire once when the pointer enters or leaves an element, and do NOT bubble • mouseover / mouseout — similar, but DO bubble and also fire when moving between an element's children • pointerdown / pointerup / pointermove / pointercancel — the unified mouse+touch+pen equivalents
Keyboard events
Keyboard events fire when the user presses or releases a key while a focusable element (like an <input>, a <textarea>, or any element with tabindex) has focus. There are two events you should use today: keydown, which fires as soon as a key is pressed (and repeats if held down), and keyup, which fires once when the key is released.
A third event, keypress, used to exist for detecting character-producing keys specifically, but it is deprecated and inconsistent across browsers — modern code uses keydown/keyup exclusively. On the event object, event.key gives you the human-readable value of the key that was pressed (for example "Enter", "a", "Shift"), while event.code gives you the physical key on the keyboard layout (for example "KeyA") regardless of what character it produces — prefer event.key for most logic, and event.code only when you specifically need the physical key position (like WASD game controls).
Form-related events
input fires immediately, every time the value of an <input>, <textarea>, or <select> changes — essentially on every keystroke, paste, or selection change. change fires only after the value has been committed and the element loses focus (for a text field) or is toggled (for a checkbox, radio, or select) — it fires far less often than input.
submit fires on the <form> element itself (not on the button) when the form is about to be submitted, whether that submission was triggered by clicking a submit button or by pressing Enter inside a text field. It is almost always paired with event.preventDefault() to stop the browser's default full-page-reload submission so JavaScript can handle the data instead.
Focus events
focus fires when an element receives keyboard or programmatic focus, and blur fires when it loses focus. Both are useful for things like highlighting the active field in a form or running validation once the user leaves a field.
A subtlety: focus and blur do not bubble, so a listener on a parent container will not catch focus events from its children. If you need bubbling behavior (for example, to know when focus moves anywhere inside a form), use focusin and focusout instead — functionally identical, but they do bubble.
Page lifecycle events
DOMContentLoaded fires on the document as soon as the initial HTML has been fully parsed and the DOM tree is built, without waiting for stylesheets, images, or other subresources to finish loading. This is normally the right moment to start running JavaScript that queries or manipulates the page.
load fires later, on the window object, only after the entire page — HTML, CSS, images, iframes, and every other resource — has finished loading. Use load only when you genuinely need to know that everything (like an image's real dimensions) is ready; for most "run my script once the page exists" needs, DOMContentLoaded is faster and more appropriate.
Registering a listener for any event type
target can be any DOM element, document, or window — whichever object the event is dispatched on. "eventType" is a plain string with no "on" prefix — "click", not "onclick". The callback receives one argument, the event object, describing what happened.
target.addEventListener("eventType", function (event) {
// event.type, event.target, and other details are available here
});Code Examples
This registers a click listener on a button. Every time the button is clicked, the browser calls the function and hands it an event object whose type property confirms what kind of event fired. Expected result: Button clicked: click event.type reports "click" here, but the same handler shape works for every event type the browser supports.
Typing "cat" into the field and then clicking elsewhere fires input three times (once per keystroke) but change only once, after the field loses focus with a new committed value. Expected result: input fired, count: 1 input fired, count: 2 input fired, count: 3 change fired, count: 1 input tracks every keystroke live; change only fires once the value is finalized.
Common mistake: A common mistake is using change to build a live-search or character-counter feature — by the time change fires, the user has already moved on, so the UI feels laggy. Use input for anything that should react immediately.
On a page with a large hero image, DOMContentLoaded typically logs almost instantly, while load only logs once that image (and every other resource) has fully downloaded. Expected result: DOM is ready, HTML parsed Everything (images, CSS, etc.) has finished loading
DOMContentLoaded fires on document; load fires on window, and always fires after DOMContentLoaded.
const button = document.querySelector("#save-btn");
button.addEventListener("click", function (event) {
console.log("Button clicked:", event.type);
});const search = document.querySelector("#search-input");
let changeCount = 0;
let inputCount = 0;
search.addEventListener("input", function () {
inputCount++;
console.log("input fired, count:", inputCount);
});
search.addEventListener("change", function () {
changeCount++;
console.log("change fired, count:", changeCount);
});document.addEventListener("DOMContentLoaded", function () {
console.log("DOM is ready, HTML parsed");
});
window.addEventListener("load", function () {
console.log("Everything (images, CSS, etc.) has finished loading");
});Important Rules
Every DOM element, plus document and window, can be an event target.
input fires on every value change; change fires only once the value is committed.
mouseenter/mouseleave/focus/blur do not bubble; mouseover/mouseout/focusin/focusout do.
DOMContentLoaded (HTML parsed) always fires before load (everything finished loading).
Where this shows up
Real interfaces combine many event types at once: input for a live character counter, keydown to let Enter submit a search box, submit with preventDefault to send form data via fetch instead of a full page reload, and DOMContentLoaded to know it is safe to start querying the DOM. Recognizing which event type actually matches the behavior you want is one of the most common everyday JavaScript decisions.
search.addEventListener("change", updateLiveResults); // to filter results as the user types search.addEventListener("input", updateLiveResults);
change only fires after the field loses focus, so a live-filtering search box built on change will feel broken — nothing updates until the user clicks away.
[Multiple Choice] Which event fires on every keystroke as a user types into a text input? A. change B. input C. keypress D. submit
B. input — input fires immediately on every value change, including each keystroke. change waits until the field loses focus.
[True / False] DOMContentLoaded always fires after the window's load event. A. True B. False
B. False — False — it is the opposite. DOMContentLoaded fires once the HTML is parsed; load fires later, once every resource (images, stylesheets, etc.) has finished loading.
Given an <input id="username"> and a <p id="status">, write code that updates the paragraph's text to "Typing..." on every keystroke (input event) and to "Done" once the field loses focus with a value (change event).
const input = document.querySelector("#username"); const status = document.querySelector("#status"); input.addEventListener("input", function () { status.textContent = "Typing..."; }); input.addEventListener("change", function () { status.textContent = "Done"; });
Attach two separate listeners to the same element, one for "input" and one for "change".