JavaScriptBeginner

JavaScript Events: click, input, submit, mouse and keyboard

Learn what events are and how to react to clicks, typing, form submits, mouse moves and key presses in JavaScript

All JavaScript lessons

What you will learn

A web page that never reacts is just a poster. Real pages respond to the user: a click opens a menu, typing filters a list, a form is checked before it is sent, a key press moves a game character. All of these are events. In this lesson you will learn what events are, three ways to attach code to them, and the most important event types: click, input, submit, mouse, keyboard and form events. You will build small, real features with each.

What is an event?

An event is a signal from the browser that something happened: the user clicked, a key went down, a form was sent, the page finished loading. The browser creates these signals all the time. Your job is to say: “When this happens to this element, run this function.”

Think of a doorbell. The event is the bell ringing. The event listener is you, waiting at home. The handler (or callback) is what you do when it rings: open the door. If nobody is listening, the bell rings and nothing happens.

JavaScript in the browser is event-driven: most of your code sits waiting and runs only when an event arrives.

Every event has three parts:

Part Question Example
Target On which element did it happen? The “Join” button
Type What happened? "click"
Handler What should run? A function that shows a message

Three ways to attach a handler

1. Inline HTML attribute (avoid)

<button onclick="alert('Hello!')">Say hello</button>

It works, but it mixes JavaScript into HTML, gets messy fast, and only allows simple cases. Real projects avoid it. You will still see it in old tutorials.

2. DOM property (onclick)

const button = document.getElementById("counter");

button.onclick = function () {
  console.log("Clicked!");
};

Simple, but there is only one onclick slot. A second assignment replaces the first:

button.onclick = function () { console.log("A"); };
button.onclick = function () { console.log("B"); };   // A is gone. Only B runs.

3. addEventListener (use this)

button.addEventListener("click", function () {
  console.log("Clicked!");
});

You can add as many listeners as you like to the same element and event, and they all run, in the order you added them:

button.addEventListener("click", function () { console.log("A"); });
button.addEventListener("click", function () { console.log("B"); });   // click prints A, then B

This is the modern and recommended way. The next lessons cover it deeply (removeEventListener, options like once, and more). In this lesson, we will use it in its basic form:

element.addEventListener("eventName", handlerFunction);
Inline onclick="" el.onclick = fn addEventListener
JavaScript stays out of HTML No Yes Yes
Many handlers on one event No No Yes
Can be removed later Hard Set to null removeEventListener
Modern projects Avoid Rare Standard

Pass the function, do not call it

The handler must be a function reference. If you add parentheses, you call it right now, instead of when the event happens:

function sayHi() {
  console.log("Hi!");
}

button.addEventListener("click", sayHi);      // correct: runs on click
button.addEventListener("click", sayHi());    // wrong: runs immediately, and passes undefined

If you need to pass your own arguments, wrap the call in another function:

button.addEventListener("click", function () {
  greet("Riya");
});

button.addEventListener("click", () => greet("Riya"));   // arrow function version

The sample page

The examples below use this page, also loaded in Practice in Editor:

<h1>Events Practice</h1>

<button id="counter">Clicked 0 times</button>

<p>
  <input id="name" type="text" placeholder="Type your name">
  <span id="greeting"></span>
</p>

<div id="box" class="box">Hover, click and move your mouse here</div>
<p id="mouse-info">Mouse: -</p>

<p id="key-info">Press any key</p>

<form id="form">
  <input id="email" type="email" placeholder="Your email">
  <select id="plan">
    <option value="free">Free</option>
    <option value="pro">Pro</option>
  </select>
  <button type="submit">Join</button>
</form>
<p id="form-info"></p>
.box {
  width: 280px;
  padding: 30px;
  text-align: center;
  border: 2px solid #94a3b8;
  border-radius: 8px;
  user-select: none;
}

.box.hover {
  background: #dbeafe;
}

Mouse events

Event When it fires
click The user presses and releases the main button (also for Enter/Space on a focused button)
dblclick Two quick clicks
contextmenu Right-click (the context menu is about to open)
mousedown / mouseup The button goes down / comes up
mouseenter / mouseleave The pointer enters / leaves the element
mouseover / mouseout Like the above, but they also fire again when the pointer moves between child elements
mousemove The pointer moves over the element (fires very often)

The click counter

The “Hello World” of events:

const counter = document.getElementById("counter");
let clicks = 0;

counter.addEventListener("click", function () {
  clicks++;
  counter.textContent = "Clicked " + clicks + " times";
});

Hover effects

const box = document.getElementById("box");

box.addEventListener("mouseenter", function () {
  box.classList.add("hover");
});

box.addEventListener("mouseleave", function () {
  box.classList.remove("hover");
});

(For a simple colour change like this, CSS :hover is better. Use JavaScript when the hover must do more, such as show a popup or load data.)

mouseenter vs mouseover

Use mouseenter and mouseleave for normal hover effects. mouseover and mouseout repeat when the pointer crosses into a child element, which causes flickering effects. Choose the first pair unless you have a special reason.

Mouse position

Mouse events give you an event object with the coordinates. The event object is the topic of the next lesson, so here is just a taste:

const mouseInfo = document.getElementById("mouse-info");

box.addEventListener("mousemove", function (event) {
  mouseInfo.textContent = "Mouse: x=" + event.offsetX + ", y=" + event.offsetY;
});

The browser passes the event object as the first argument of your handler. You may name it event, e or evt.

Tip: mousemove can fire many times per second. Keep its code light. A later lesson on debounce and throttle shows how to slow it down.

Keyboard events

Event When it fires
keydown A key goes down. It repeats while the key is held
keyup A key comes up
keypress Old and deprecated. Do not use it. Use keydown
document.addEventListener("keydown", function (event) {
  document.getElementById("key-info").textContent = "You pressed: " + event.key;
});

Here we listen on document, so keys are caught wherever the focus is. Listen on an <input> instead to catch only keys typed in that input.

event.key is the character or name of the key: "a", "A", "5", "Enter", "Escape", " " (space), "ArrowUp". The next lesson covers key vs code in detail.

Do something on a specific key

const messageInput = document.getElementById("name");

messageInput.addEventListener("keydown", function (event) {
  if (event.key === "Enter") {
    console.log("Send:", messageInput.value);
  }

  if (event.key === "Escape") {
    messageInput.value = "";
  }
});

Form and input events

Forms have the most events, and they are used in almost every real website.

Event On When it fires
input <input>, <textarea>, <select> Every time the value changes, instantly (each key, paste, delete)
change Form controls When the change is finished: a text input when it loses focus, a select/checkbox/radio at once
focus / blur Form controls The element gets / loses focus (they do not bubble)
focusin / focusout Any element Like focus and blur, but they bubble
submit <form> The form is being sent (Join button or Enter key)
reset <form> The form is reset

input: react while typing

const nameInput = document.getElementById("name");

nameInput.addEventListener("input", function () {
  document.getElementById("greeting").textContent = "Hello, " + nameInput.value + "!";
});

input vs change

For a text box, input fires on every key and change fires only when you leave the box (or press Enter). For a dropdown, checkbox or radio, both fire when you pick an option.

const plan = document.getElementById("plan");

plan.addEventListener("change", function () {
  console.log("Selected plan:", plan.value);
});
I want to… Use
Update live while typing (search, counter, preview) input
React to a finished choice (dropdown, checkbox, date) change
Validate when the user leaves a field blur or change

focus and blur

const email = document.getElementById("email");

email.addEventListener("focus", function () {
  email.style.outline = "2px solid #2563eb";
});

email.addEventListener("blur", function () {
  email.style.outline = "";
  if (!email.value.includes("@")) {
    console.log("Please enter a valid email");
  }
});

submit: handle the whole form

A form is submitted when the user clicks a submit button or presses Enter in a field. Always listen for submit on the form, not for click on the button, or the Enter key will skip your code.

By default, the browser sends the form and reloads the page. To handle it yourself with JavaScript, call event.preventDefault() (the next lessons explain this fully):

const form = document.getElementById("form");

form.addEventListener("submit", function (event) {
  event.preventDefault();   // stop the page reload

  const email = document.getElementById("email").value;
  document.getElementById("form-info").textContent = "Submitted: " + email;
});

Tip: A <button> inside a form is a submit button by default. If you want a button that does something else, such as “Show password”, write type="button" so it does not submit the form.

Page events

Not every event comes from the user:

Event On When it fires
DOMContentLoaded document The HTML is read and the DOM is ready
load window The page and all images and files finished loading
resize window The browser window size changes
scroll window or a scrollable element The user scrolls
document.addEventListener("DOMContentLoaded", function () {
  console.log("The DOM is ready");
});

window.addEventListener("resize", function () {
  console.log("Width now:", window.innerWidth);
});

Real use cases

1. Live search filter

Type in the box and the list shows only the matching items. This uses input, toLowerCase, includes and a hidden toggle.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Live Search</title>
  <style>
    body { font-family: sans-serif; padding: 20px; max-width: 360px; }
    input { width: 100%; padding: 8px; font-size: 16px; box-sizing: border-box; }
    ul { padding-left: 20px; }
    li { padding: 4px 0; }
  </style>
</head>
<body>
  <label for="search">Search a language</label>
  <input id="search" type="text" placeholder="Type to filter...">

  <ul id="languages">
    <li>JavaScript</li>
    <li>Python</li>
    <li>Java</li>
    <li>TypeScript</li>
    <li>C++</li>
    <li>Rust</li>
  </ul>
  <p id="none" hidden>No match found.</p>

  <script>
    const search = document.getElementById("search");
    const items = document.querySelectorAll("#languages li");
    const none = document.getElementById("none");

    search.addEventListener("input", function () {
      const query = search.value.trim().toLowerCase();
      let visible = 0;

      items.forEach(function (item) {
        const match = item.textContent.toLowerCase().includes(query);
        item.hidden = !match;
        if (match) visible++;
      });

      none.hidden = visible > 0;
    });
  </script>
</body>
</html>

2. Keyboard shortcut

Many apps use shortcuts like Ctrl + K for search or Escape to close a popup.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Shortcuts</title>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    input { padding: 8px; font-size: 16px; width: 260px; }
    #modal { display: none; margin-top: 16px; padding: 16px; border: 2px solid #2563eb; border-radius: 8px; max-width: 260px; }
    #modal.open { display: block; }
  </style>
</head>
<body>
  <p>Press <kbd>Ctrl</kbd> + <kbd>K</kbd> to focus the search. Press <kbd>M</kbd> to open the box and <kbd>Esc</kbd> to close it.</p>

  <input id="search" type="text" placeholder="Search...">
  <div id="modal">I am a popup box.</div>

  <script>
    const search = document.getElementById("search");
    const modal = document.getElementById("modal");

    document.addEventListener("keydown", function (event) {
      if (event.ctrlKey && event.key.toLowerCase() === "k") {
        event.preventDefault();        // stop the browser's own shortcut
        search.focus();
      }

      // ignore single letters while the user is typing in the input
      if (document.activeElement === search) return;

      if (event.key.toLowerCase() === "m") modal.classList.add("open");
      if (event.key === "Escape") modal.classList.remove("open");
    });
  </script>
</body>
</html>

3. Contact form with validation

A realistic form: check on blur for each field, and again on submit. Error messages use textContent, and the input gets a class (from the classList lesson).

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Contact Form</title>
  <style>
    body { font-family: sans-serif; padding: 20px; max-width: 360px; }
    label { display: block; margin-top: 12px; }
    input, textarea { width: 100%; padding: 8px; font-size: 16px; box-sizing: border-box; border: 2px solid #d1d5db; border-radius: 6px; }
    .invalid { border-color: #dc2626; }
    .error { color: #dc2626; font-size: 14px; min-height: 18px; margin: 4px 0 0; }
    button { margin-top: 12px; padding: 10px 16px; font-size: 16px; cursor: pointer; }
    #success { color: #15803d; font-weight: bold; }
  </style>
</head>
<body>
  <form id="contact" novalidate>
    <label for="cname">Name</label>
    <input id="cname" type="text">
    <p class="error" id="cname-error"></p>

    <label for="cemail">Email</label>
    <input id="cemail" type="email">
    <p class="error" id="cemail-error"></p>

    <button type="submit">Send</button>
  </form>
  <p id="success"></p>

  <script>
    const form = document.getElementById("contact");
    const nameInput = document.getElementById("cname");
    const emailInput = document.getElementById("cemail");

    function check(input, message, isValid) {
      const error = document.getElementById(input.id + "-error");
      input.classList.toggle("invalid", !isValid);
      error.textContent = isValid ? "" : message;
      return isValid;
    }

    function checkName() {
      return check(nameInput, "Please enter at least 2 characters.", nameInput.value.trim().length >= 2);
    }

    function checkEmail() {
      return check(emailInput, "Please enter a valid email.", /^\S+@\S+\.\S+$/.test(emailInput.value));
    }

    nameInput.addEventListener("blur", checkName);     // when leaving the field
    emailInput.addEventListener("blur", checkEmail);

    form.addEventListener("submit", function (event) {
      event.preventDefault();

      const nameOk = checkName();
      const emailOk = checkEmail();

      document.getElementById("success").textContent =
        nameOk && emailOk ? "Thank you! We will contact you soon." : "";
    });
  </script>
</body>
</html>

Here checkName and checkEmail are passed by name (without parentheses) as handlers, and are also called by hand inside submit. The email pattern is a regular expression, which you studied in the regex lesson.

4. Click a button, show a message

The most common beginner feature, short and useful:

const likeButton = document.getElementById("like");
let likes = 0;

likeButton.addEventListener("click", function () {
  likes++;
  likeButton.textContent = "👍 " + likes;
});

5. Tooltip that follows the mouse

const tip = document.getElementById("tip");   // a small absolutely positioned <div>
const area = document.getElementById("area");

area.addEventListener("mousemove", function (event) {
  tip.style.left = event.clientX + 12 + "px";
  tip.style.top = event.clientY + 12 + "px";
});

area.addEventListener("mouseenter", function () { tip.hidden = false; });
area.addEventListener("mouseleave", function () { tip.hidden = true; });

Common mistakes

  • Calling the function instead of passing it. addEventListener("click", sayHi()) runs sayHi at once. Write sayHi, or wrap it: () => sayHi().
  • Using onclick twice. The second one replaces the first. Use addEventListener.
  • Running the script before the element exists. getElementById returns null, and null.addEventListener crashes. Put the script at the end of <body>, or use defer (see the DOM introduction).
  • Mistyping the event name. "onclick" is wrong for addEventListener. It is "click", with no on. Event names are lowercase.
  • Listening for click on a submit button instead of submit on the form. The Enter key then skips your code.
  • Forgetting preventDefault() on a form. The page reloads and your result disappears.
  • Expecting change on every key. A text box fires change only when you leave it. Use input.
  • Using keypress. It is deprecated. Use keydown.
  • Adding listeners inside a loop or another handler again and again. The same handler then runs many times. Add it once.
  • Doing heavy work in mousemove, scroll or resize. They fire hundreds of times. Keep them light.
  • A <button> in a form that should not submit. Add type="button".

Practice

  1. Make a button that counts clicks. Add a second button that resets the counter.
  2. Show what the user types live in a paragraph below an input (use the input event).
  3. Change the text of the box on dblclick, and make it highlighted on mouseenter and normal on mouseleave.
  4. Show the event.key of every key pressed on the page. What do you see when you press space, Enter, and the arrow keys?
  5. Add a change listener to a <select> and print the new value. Then add a checkbox and print whether it is checked.
  6. Make the form show "Welcome, <email>" on submit without reloading the page. Test it by pressing Enter inside the email field instead of clicking the button.
  7. Compare input and change on the same text box by logging both. When does each one fire?
  8. Build the live search filter, and add a counter that says how many items are visible (for example, 3 of 6 shown).
  9. Make a character counter for a <textarea> that stops showing red once the user is under the limit again.
  10. Challenge: build a small “guess the key” game. Choose a random letter. When the user presses a key, tell them if it matches, and show how many tries they took.

Recap

  • An event is a signal that something happened. Event-driven code waits for events and then runs a handler function.
  • The best way to listen is element.addEventListener("click", handler). Event names have no on prefix. Avoid inline onclick="", and note that el.onclick = ... allows only one handler.
  • Pass the function itself (handler), not a call (handler()).
  • Mouse: click, dblclick, contextmenu, mousedown, mouseup, mouseenter, mouseleave, mousemove. Prefer mouseenter/mouseleave for hover.
  • Keyboard: keydown and keyup. Use event.key to know which key. Do not use keypress.
  • Form: input (live), change (finished), focus, blur, submit and reset. Listen to submit on the form and call preventDefault() to stop the reload.
  • Page: DOMContentLoaded, load, resize and scroll. Keep the busy ones (mousemove, scroll, resize) light.
  • Events power real features: counters, live search, shortcuts, validation and tooltips.
  • Next you will learn the event object: the information the browser gives you about every event, such as event.target.