Browser Events, Forms & Event Delegation (The Complete Masterclass)
Welcome to Phase 12: Events and Forms! In modern web applications, Browser Events serve as notifications for user interactions (clicks, keyboard strokes, typing, mouse hovers, form submissions, scrolling) or browser lifecycle changes. In this comprehensive masterclass guide, you will learn how to handle events with addEventListener(), master the Event Object (e.target, e.currentTarget), understand Event Bubbling vs Capturing, leverage high-performance Event Delegation, prevent default browser actions with e.preventDefault(), build robust real-time Form Validation engines, and construct 6 complete interactive web applications.
User mouse tho click chesinappudu, keyboard lo key press chesinappudu, or form submit chesinappudu browser generate chese signals ni Events antaru. JavaScript ee events ni addEventListener(eventType, handlerCallback, options) dwara listen chesthundhi:
// element.addEventListener(event, callbackFunction)
const btn = document.querySelector("#submitBtn");
btn.addEventListener("click", (e) => {
console.log("Button clicked at coordinates:", e.clientX, e.clientY);
});
| Category | Event Names | When does it trigger? |
|---|---|---|
| Mouse Events | 'click', 'dblclick', 'mouseenter', 'mouseleave', 'mousemove' |
Clicking, double-clicking, cursor entering or hovering over an element. |
| Keyboard Events | 'keydown', 'keyup' |
Key is pressed down or released. Read e.key (e.g. "Enter", "Escape"). |
| Input & Change | 'input', 'change' |
'input' triggers immediately on every typed letter; 'change' triggers when input loses focus after value change. |
| Form Events | 'submit', 'reset' |
User clicks submit button or hits Enter in a form. |
| Focus Events | 'focus', 'blur' |
'focus' occurs when input is highlighted; 'blur' occurs when user clicks away. |
User nijamga ae specific inner element ni click chesado aa exact DOM node ki point chesthundi (e.g. inner icon inside a button).
Ae parent element ki addEventListener attach chesamo aa container element ki point chesthundhi (equivalent to this).
HTML element meedha event trigger avvagane 3 phases jaruguthayi:
- Capturing Phase: Event Window nunchi Document $ ightarrow$ Body $ ightarrow$ Parent $ ightarrow$ Target daka kindhaki travel avthundhi.
- Target Phase: Clicked element daggara event trigger avthundhi.
- Bubbling Phase (Default): Event Target nunchi Parent $ ightarrow$ Body $ ightarrow$ Window daka เฐชเฑเฐเฐฟ bubble avthundhi.
100 list items unte 100 listeners pettakunda, common parent <ul> ki **single event listener** petti e.target.closest('li') tho identify cheyyadanni **Event Delegation** antaru. Memory consumption massive ga taggutundi!
"use strict";
const list = document.querySelector("#todoList");
// Single listener on parent UL handling all children (even future added items!)
list.addEventListener("click", (e) => {
const deleteBtn = e.target.closest(".delete-btn");
if (deleteBtn) {
const item = deleteBtn.closest("li");
item.remove(); // Delete item
}
});
HTML forms submit chesinappudu browser default ga entire page ni reload chesthundhi. Single Page Applications (SPA) lo e.preventDefault() call chesi page reload ni prevent chesi, JavaScript tho data validate cheyyali:
"use strict";
const form = document.querySelector("#loginForm");
const emailInput = document.querySelector("#email");
const passwordInput = document.querySelector("#password");
const errorBox = document.querySelector("#errorMessage");
form.addEventListener("submit", (e) => {
e.preventDefault(); // 1. Stop default page reload!
const email = emailInput.value.trim();
const password = passwordInput.value;
// 2. Validate
if (!email || !email.includes("@")) {
errorBox.textContent = "โ Please enter a valid email address!";
emailInput.style.borderColor = "#ff7b72";
return;
}
if (password.length < 6) {
errorBox.textContent = "โ Password must be at least 6 characters!";
passwordInput.style.borderColor = "#ff7b72";
return;
}
// 3. Success
errorBox.textContent = "โ
Login Successful! Redirecting...";
errorBox.style.color = "#3fb950";
form.reset(); // Clear form
});
Mastering events & forms through 6 production-grade browser components:
Project 1: Interactive Login Form with Live Error Feedback
<form id="authForm" style="max-width:320px; display:flex; flex-direction:column; gap:10px;">
<input type="email" id="authEmail" placeholder="Email Address" required>
<input type="password" id="authPassword" placeholder="Password" required>
<button type="submit">Sign In</button>
<div id="authAlert" style="font-size:13px;"></div>
</form>
<script>
document.querySelector("#authForm").addEventListener("submit", (e) => {
e.preventDefault();
const email = document.querySelector("#authEmail").value;
const alertBox = document.querySelector("#authAlert");
alertBox.innerHTML = '<span style="color:#3fb950;">Welcome back, ' + email + '!</span>';
});
</script>
Project 2: Contact Form with Reset Handler
const contactForm = document.querySelector("#contactForm");
contactForm.addEventListener("submit", (e) => {
e.preventDefault();
const formData = new FormData(contactForm);
console.log("Submitted Message from:", formData.get("name"), formData.get("message"));
alert("Thank you! Your message has been received.");
contactForm.reset();
});
Project 3: Production To-Do List with Event Delegation
<input type="text" id="newTodo" placeholder="Add task...">
<button id="addBtn">Add</button>
<ul id="todoContainer"></ul>
<script>
const input = document.querySelector("#newTodo");
const container = document.querySelector("#todoContainer");
document.querySelector("#addBtn").addEventListener("click", () => {
if (!input.value.trim()) return;
const li = document.createElement("li");
li.innerHTML = input.value + ' <button class="del">โ</button>';
container.append(li);
input.value = "";
});
// Single Event Delegation Listener on Parent
container.addEventListener("click", (e) => {
if (e.target.classList.contains("del")) {
e.target.parentElement.remove();
}
});
</script>
Project 4: Real-Time Live Search Filter
<input type="text" id="searchBox" placeholder="Search framework...">
<ul id="frameworkList">
<li>React.js</li>
<li>Next.js</li>
<li>Vue.js</li>
<li>Angular</li>
<li>Node.js</li>
</ul>
<script>
const searchBox = document.querySelector("#searchBox");
const items = document.querySelectorAll("#frameworkList li");
searchBox.addEventListener("input", (e) => {
const query = e.target.value.toLowerCase();
items.forEach(li => {
const text = li.textContent.toLowerCase();
li.style.display = text.includes(query) ? "block" : "none";
});
});
</script>
Project 5: Character Counter with 200 Max Limit
<textarea id="tweetBox" maxlength="200" placeholder="What's happening?"></textarea>
<div id="charStatus">200 characters remaining</div>
<script>
const tweetBox = document.querySelector("#tweetBox");
const charStatus = document.querySelector("#charStatus");
const MAX_CHARS = 200;
tweetBox.addEventListener("input", () => {
const remaining = MAX_CHARS - tweetBox.value.length;
charStatus.textContent = remaining + " characters remaining";
charStatus.style.color = remaining < 20 ? "#ff7b72" : "#3fb950";
});
</script>
Project 6: Interactive Quiz App Engine
<div id="quizCard">
<h3>Which keyword declares a block-scoped constant?</h3>
<button class="quiz-opt" data-correct="false">var</button>
<button class="quiz-opt" data-correct="true">const</button>
<button class="quiz-opt" data-correct="false">let</button>
<div id="quizResult" style="margin-top:10px; font-weight:700;"></div>
</div>
<script>
document.querySelector("#quizCard").addEventListener("click", (e) => {
if (e.target.classList.contains("quiz-opt")) {
const isCorrect = e.target.dataset.correct === "true";
const result = document.querySelector("#quizResult");
if (isCorrect) {
result.textContent = "๐ Correct Answer! 'const' is block-scoped.";
result.style.color = "#3fb950";
} else {
result.textContent = "โ Wrong Answer! Try again.";
result.style.color = "#ff7b72";
}
}
});
</script>