Skip to content
JavaScript js events 5 min read

The Event Object

Every time an event fires, the browser hands your handler a single argument: the event object. It is a snapshot of what just happened — which element was involved, what type of event it was, where the pointer was, which key was pressed, and any data specific to that event. Reading these properties is how a generic handler decides what to actually do, so knowing the event object well is the key to writing flexible, reusable event code.

Receiving the event object

The browser always passes the event object as the first parameter to your listener. By convention it is named event, e, or evt. You never construct it yourself for native events — you just accept it and read from it.

button.addEventListener('click', (event) => {
  console.log(event.type);      // "click"
  console.log(event.target);    // the element that was clicked
  console.log(event.timeStamp); // ms since the page loaded
});

The object you receive is an instance of a specialized subclass — MouseEvent for clicks, KeyboardEvent for key presses, InputEvent for typing, and so on. Each subclass adds properties relevant to its event, all built on the base Event interface.

Properties shared by every event

These live on the base Event interface, so they are available no matter what fired.

PropertyDescription
typeThe event name as a string, e.g. "click", "keydown".
targetThe element that originally dispatched the event.
currentTargetThe element whose listener is currently running.
timeStampMilliseconds since page load when the event was created.
bubblesWhether the event travels up the DOM tree.
defaultPreventedtrue if preventDefault() has been called.
isTrustedtrue for real user actions, false for scripted dispatches.

target vs currentTarget

This pair trips up almost everyone, and the distinction matters most when handling events on a parent. target is where the event started — the deepest element that was actually clicked. currentTarget is where the listener is attached — the element you called addEventListener on. During bubbling they can be different.

list.addEventListener('click', (e) => {
  // e.currentTarget is always `list`
  // e.target is the specific <li> (or child) you clicked
  console.log(e.currentTarget === list);      // true
  console.log(e.target.tagName);              // e.g. "LI"
});

Inside an arrow function, this is not the element. Use e.currentTarget to reliably reference the element the handler is bound to — it works in both arrow and regular functions.

Mouse coordinates

MouseEvent exposes several coordinate systems. They answer different questions, so pick the one that matches what you need.

PropertyOrigin
clientX / clientYTop-left of the visible viewport.
pageX / pageYTop-left of the whole document (includes scroll).
offsetX / offsetYTop-left of the target element itself.
screenX / screenYTop-left of the physical screen.

Use clientX/Y for fixed overlays, pageX/Y when scroll position counts, and offsetX/Y for drawing relative to an element such as a <canvas>.

Keyboard information

KeyboardEvent tells you what was pressed in two complementary ways. key is the produced character or named value ("a", "Enter", "ArrowUp"), affected by Shift and keyboard layout. code is the physical key ("KeyA", "Enter", "ArrowUp"), independent of layout — ideal for game controls like WASD.

document.addEventListener('keydown', (e) => {
  if (e.key === 'Escape') closeModal();
  if (e.ctrlKey && e.key === 's') {
    e.preventDefault();
    saveDocument();
  }
});

Output:

// Pressing Ctrl+S logs nothing but blocks the browser's Save dialog
// Pressing Escape calls closeModal()

The modifier flags ctrlKey, shiftKey, altKey, and metaKey (Cmd on macOS, Win key on Windows) are booleans you combine with key to detect shortcuts.

Live demo: mouse and keyboard info

Move your mouse and press keys over the box below to watch the event object’s properties update in real time.

<div id="stage" tabindex="0"
     style="font-family:system-ui;padding:24px;border:2px solid #6366f1;border-radius:12px;outline:none;cursor:crosshair;user-select:none">
  <strong>Click here, move the mouse, then type.</strong>
  <pre id="readout" style="margin-top:12px;color:#334155">waiting…</pre>
</div>
<script>
  const stage = document.getElementById('stage');
  const readout = document.getElementById('readout');

  stage.addEventListener('mousemove', (e) => {
    readout.textContent =
      `type: ${e.type}\n` +
      `client: ${e.clientX}, ${e.clientY}\n` +
      `offset: ${e.offsetX}, ${e.offsetY}`;
  });

  stage.addEventListener('keydown', (e) => {
    readout.textContent =
      `type: ${e.type}\n` +
      `key: ${e.key}\n` +
      `code: ${e.code}\n` +
      `modifiers: ${[e.ctrlKey && 'Ctrl', e.shiftKey && 'Shift', e.altKey && 'Alt']
        .filter(Boolean).join('+') || 'none'}`;
    e.preventDefault();
  });
</script>

Event-specific data

Beyond the basics, each event type carries its own payload. Reading the right property saves you from querying the DOM separately.

  • input events expose e.target.value (the current text) and e.inputType (e.g. "insertText", "deleteContentBackward").
  • wheel events give e.deltaX/deltaY/deltaZ for scroll direction and amount.
  • submit events let you read the form via e.target and prevent navigation with e.preventDefault().
  • Drag events carry a e.dataTransfer object; clipboard events carry e.clipboardData.
<form id="signup" style="font-family:system-ui">
  <input id="email" type="email" placeholder="[email protected]"
         style="padding:8px;border:1px solid #cbd5e1;border-radius:6px" />
  <p id="status" style="color:#475569">Type an email…</p>
</form>
<script>
  const form = document.getElementById('signup');
  const status = document.getElementById('status');

  form.addEventListener('input', (e) => {
    const valid = e.target.validity.valid && e.target.value.length > 0;
    status.textContent = valid ? '✓ looks valid' : 'keep typing…';
    status.style.color = valid ? '#16a34a' : '#475569';
  });

  form.addEventListener('submit', (e) => {
    e.preventDefault(); // stop the page from reloading
    status.textContent = `Submitted: ${form.email.value}`;
  });
</script>

Best Practices

  • Name the parameter event or e and read from it rather than reaching back into the DOM.
  • Use e.currentTarget (not this) for the bound element so your code works with arrow functions.
  • Reach for e.target when you need the exact element the user interacted with — essential for delegation.
  • Prefer e.code for physical key bindings (games, shortcuts) and e.key for text and named keys.
  • Pick the coordinate system deliberately: offsetX/Y for element-relative drawing, clientX/Y for viewport overlays.
  • Check e.isTrusted if a handler must only respond to genuine user input, not scripted dispatches.
Last updated June 1, 2026
Was this helpful?