Events and Forms
Listening for events
button.addEventListener("click", (event) => {
console.log("clicked", event.target);
});
input.addEventListener("input", () => counter.textContent = input.value.length);
window.addEventListener("keydown", (e) => {
if (e.key === "Escape") closeModal();
});
Common events: click, input, change, submit, keydown, focus, blur, scroll, DOMContentLoaded.
Forms
<form id="signup" novalidate>
<label>Email <input type="email" name="email" required></label>
<label>Password <input type="password" name="password" minlength="8" required></label>
<p class="error" id="formError" hidden></p>
<button>Create account</button>
</form>
const form = document.querySelector("#signup");
form.addEventListener("submit", (event) => {
event.preventDefault(); // stop the full page reload
const data = Object.fromEntries(new FormData(form));
if (!form.checkValidity()) {
showError("Please fill in a valid email and an 8+ character password.");
return;
}
submitSignup(data);
});
HTML attributes (required, type="email", minlength, pattern) give you validation for free. JavaScript validation improves the experience, but the server must validate again: anyone can bypass browser checks.
Event delegation
Instead of one listener per item (including items added later), listen on the parent:
document.querySelector("#tasks").addEventListener("click", (event) => {
const deleteBtn = event.target.closest("button.delete");
if (!deleteBtn) return;
deleteBtn.closest("li").remove();
});
closest() walks up from the clicked element, so clicks on an icon inside the button still work.
Debouncing
Searching on every keystroke can flood your server. Wait until the user pauses:
function debounce(fn, ms = 300) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), ms);
};
}
search.addEventListener("input", debounce(() => runSearch(search.value)));
Accessibility
Use real <button> and <a> elements instead of clickable <div>s: they work with the keyboard and screen readers automatically. Associate every input with a <label>.
Exercise
Build a sign-up form that checks the passwords match, shows inline errors next to each field as the user types, disables the button until valid, and logs the data on submit without reloading.
Check yourself
- What does
event.preventDefault()do on a form? - Why must the server validate even if the browser does?
- How does event delegation handle elements added later?
Your progress is saved in this browser only.
Submit for review (10 points)