Chapter 12 Intermediate 60 Questions

Practice Questions — DOM Events and Event Listeners

← Back to Notes
10 Easy
11 Medium
9 Hard

Topic-Specific Questions

Question 1
Easy
What happens when the button is clicked?
<button id="btn">Click Me</button>
<p id="msg">Waiting...</p>

<script>
document.getElementById("btn").addEventListener("click", function() {
  document.getElementById("msg").textContent = "Button clicked!";
});
</script>
The click handler changes the paragraph text.
When the button is clicked, the paragraph text changes from "Waiting..." to "Button clicked!".
Question 2
Easy
What is logged to the console when the button is clicked?
<button id="btn">Hello</button>

<script>
document.getElementById("btn").addEventListener("click", function(e) {
  console.log(e.type);
  console.log(e.target.textContent);
});
</script>
e.type gives the event type. e.target is the clicked element.
click
Hello
Question 3
Easy
What happens when you type in the input?
<input type="text" id="name">
<p id="output"></p>

<script>
document.getElementById("name").addEventListener("input", function() {
  document.getElementById("output").textContent = "Hello, " + this.value;
});
</script>
The input event fires on every keystroke. 'this' refers to the input element.
As you type, the paragraph below updates in real time. Typing "Aarav" shows "Hello, Aarav".
Question 4
Easy
What is logged when the user presses the 'a' key?
<script>
document.addEventListener("keydown", function(e) {
  console.log("Key: " + e.key);
});
</script>
e.key gives the name of the key that was pressed.
Key: a
Question 5
Easy
What happens when the form is submitted?
<form id="myForm">
  <input type="text" value="Aarav">
  <button type="submit">Go</button>
</form>

<script>
document.getElementById("myForm").addEventListener("submit", function(e) {
  e.preventDefault();
  console.log("Form submitted!");
});
</script>
preventDefault stops the page from reloading.
The console logs "Form submitted!" and the page does NOT reload.
Question 6
Medium
What is logged when the button inside the div is clicked?
<div id="outer">
  <button id="inner">Click</button>
</div>

<script>
document.getElementById("outer").addEventListener("click", function() {
  console.log("Outer");
});
document.getElementById("inner").addEventListener("click", function() {
  console.log("Inner");
});
</script>
Events bubble from child to parent.
Inner
Outer
Question 7
Medium
What is logged when the button is clicked?
<div id="parent">
  <button id="child">Click</button>
</div>

<script>
document.getElementById("parent").addEventListener("click", function() {
  console.log("Parent");
});
document.getElementById("child").addEventListener("click", function(e) {
  e.stopPropagation();
  console.log("Child");
});
</script>
stopPropagation prevents the event from bubbling up.
Child
Question 8
Medium
Given this HTML, what is logged when 'Banana' is clicked?
<ul id="fruits">
  <li>Apple</li>
  <li>Banana</li>
  <li>Cherry</li>
</ul>

<script>
document.getElementById("fruits").addEventListener("click", function(e) {
  console.log("Clicked:", e.target.textContent);
  console.log("Listener on:", e.currentTarget.id);
});
</script>
e.target is what was clicked. e.currentTarget is where the listener is attached.
Clicked: Banana
Listener on: fruits
Question 9
Medium
What is logged?
<button id="btn">Click</button>

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

btn.addEventListener("click", function() {
  console.log("First");
});

btn.addEventListener("click", function() {
  console.log("Second");
});

btn.addEventListener("click", function() {
  console.log("Third");
});
</script>
Multiple listeners on the same element run in the order they were added.
First
Second
Third
Question 10
Medium
What happens when the button is clicked?
<button id="btn">Click Me</button>

<script>
function greet() {
  console.log("Hello!");
}

const btn = document.getElementById("btn");
btn.addEventListener("click", greet);
btn.removeEventListener("click", greet);
</script>
The listener is added and then immediately removed.
Nothing happens when the button is clicked. No console output.
Question 11
Hard
What is logged when the button is clicked?
<button id="btn">Click</button>

<script>
const btn = document.getElementById("btn");
let count = 0;

function handleClick() {
  count++;
  console.log("Count: " + count);
  if (count >= 3) {
    btn.removeEventListener("click", handleClick);
    console.log("Listener removed");
  }
}

btn.addEventListener("click", handleClick);
</script>

The button is clicked 5 times.

After 3 clicks, the listener removes itself.
Count: 1
Count: 2
Count: 3
Listener removed
(Clicks 4 and 5 produce no output)
Question 12
Hard
What is logged when 'Enter' is pressed while the input is focused?
<input type="text" id="search" value="JavaScript">

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

input.addEventListener("keydown", function(e) {
  if (e.key === "Enter") {
    console.log("Searching for: " + this.value);
    console.log("Input or Textarea: " + (e.target.tagName));
  }
});
</script>
'this' in a regular function handler refers to the element the listener is on. tagName returns uppercase.
Searching for: JavaScript
Input or Textarea: INPUT
Question 13
Hard
What is logged?
<div id="container">
  <button class="btn" data-action="save">Save</button>
  <button class="btn" data-action="delete">Delete</button>
  <button class="btn" data-action="edit">Edit</button>
</div>

<script>
document.getElementById("container").addEventListener("click", function(e) {
  if (e.target.classList.contains("btn")) {
    const action = e.target.getAttribute("data-action");
    console.log("Action: " + action);
  }
});
</script>

The user clicks the 'Delete' button.

Event delegation with data attributes to determine the action.
Action: delete
Question 14
Easy
What is logged?
<input type="text" id="name">

<script>
const input = document.getElementById("name");

input.addEventListener("focus", function() {
  console.log("Focused");
});

input.addEventListener("blur", function() {
  console.log("Blurred");
});
</script>

The user clicks the input, types 'Hi', then clicks outside the input.

focus fires when the input gains focus, blur when it loses focus.
Focused
Blurred
Question 15
Medium
What is the difference in output between input and change events?
<input type="text" id="field">

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

field.addEventListener("input", function() {
  console.log("input: " + field.value);
});

field.addEventListener("change", function() {
  console.log("change: " + field.value);
});
</script>

The user types 'Hi' and then clicks outside the input.

input fires on every keystroke. change fires when the value changes AND the element loses focus.
input: H
input: Hi
change: Hi
Question 16
Hard
What is logged?
<button id="btn">Click</button>

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

btn.addEventListener("click", () => {
  console.log("this:", this === window);
});

btn.addEventListener("click", function() {
  console.log("this:", this === btn);
});
</script>
Arrow functions do not have their own 'this'. Regular functions get 'this' set to the element.
this: true
this: true
Question 17
Hard
What is logged when the user presses Ctrl+Enter?
<script>
document.addEventListener("keydown", function(e) {
  console.log("key:", e.key);
  console.log("ctrlKey:", e.ctrlKey);
  console.log("shiftKey:", e.shiftKey);
  console.log("altKey:", e.altKey);
});
</script>
Modifier key properties (ctrlKey, shiftKey, altKey) are booleans.
key: Enter
ctrlKey: true
shiftKey: false
altKey: false
Question 18
Easy
What happens when this code runs?
<button id="btn">Click Me</button>

<script>
const btn = document.getElementById("btn");
btn.addEventListener("click", function() {
  btn.textContent = "Clicked!";
  btn.disabled = true;
});
</script>
Setting disabled to true prevents further clicks.
On the first click, the button text changes to "Clicked!" and the button becomes disabled. It cannot be clicked again.

Mixed & Application Questions

Question 1
Easy
What is logged when the button is clicked twice?
<button id="btn">Toggle</button>

<script>
let isOn = false;
document.getElementById("btn").addEventListener("click", function() {
  isOn = !isOn;
  console.log(isOn);
});
</script>
!false is true, !true is false.
true
false
Question 2
Easy
What does this code do?
<a href="https://google.com" id="link">Google</a>

<script>
document.getElementById("link").addEventListener("click", function(e) {
  e.preventDefault();
  console.log("Link click prevented!");
});
</script>
preventDefault stops the default link navigation.
Clicking the link does NOT navigate to Google. Instead, "Link click prevented!" is logged to the console.
Question 3
Medium
What is logged when 'Item 2' is clicked?
<ul id="list">
  <li data-id="1">Item 1</li>
  <li data-id="2">Item 2</li>
  <li data-id="3">Item 3</li>
</ul>

<script>
document.getElementById("list").addEventListener("click", function(e) {
  if (e.target.tagName === "LI") {
    console.log("ID: " + e.target.dataset.id);
    console.log("Text: " + e.target.textContent);
  }
});
</script>
dataset gives access to data-* attributes. data-id becomes dataset.id.
ID: 2
Text: Item 2
Question 4
Medium
What is logged when the button is clicked 3 times?
<button id="btn">Click</button>
<p id="result"></p>

<script>
let clicks = [];
document.getElementById("btn").addEventListener("click", function() {
  const now = new Date();
  clicks.push(now.getSeconds());
  document.getElementById("result").textContent = clicks.join(", ");
  console.log("Clicks so far: " + clicks.length);
});
</script>
Each click adds the current second to the array.
Clicks so far: 1
Clicks so far: 2
Clicks so far: 3
Question 5
Easy
What is the difference between the input event and the change event on a text input?
One fires in real time, the other waits.
The input event fires immediately on every change to the input's value (every keystroke, paste, or deletion). The change event fires only when the value has changed AND the input loses focus (the user clicks or tabs away). Use input for real-time updates and change for final values.
Question 6
Medium
What is event delegation and why is it useful?
Think about attaching one listener vs many.
Event delegation is a pattern where you attach a single event listener to a parent element instead of individual listeners to each child. When a child is clicked, the event bubbles up to the parent, where you use e.target to identify which child triggered it. Benefits: (1) uses less memory (one listener vs many), (2) works for dynamically added elements, (3) less code to write and maintain.
Question 7
Medium
What is the difference between e.target and e.currentTarget?
One is what was clicked, the other is where the listener lives.
e.target is the actual element that was clicked (the most specific element). e.currentTarget is the element the event listener is attached to. In event delegation, e.target is the child that was clicked and e.currentTarget is the parent with the listener.
Question 8
Hard
What is logged?
<div id="outer">
  <div id="middle">
    <button id="inner">Click</button>
  </div>
</div>

<script>
document.getElementById("outer").addEventListener("click", function(e) {
  console.log("outer - target: " + e.target.id + ", currentTarget: " + e.currentTarget.id);
});
document.getElementById("middle").addEventListener("click", function(e) {
  console.log("middle - target: " + e.target.id + ", currentTarget: " + e.currentTarget.id);
});
document.getElementById("inner").addEventListener("click", function(e) {
  console.log("inner - target: " + e.target.id + ", currentTarget: " + e.currentTarget.id);
});
</script>

The button is clicked.

e.target is always the clicked element. e.currentTarget changes as the event bubbles.
inner - target: inner, currentTarget: inner
middle - target: inner, currentTarget: middle
outer - target: inner, currentTarget: outer
Question 9
Hard
What is logged? The user types 'AB' into the input.
<input type="text" id="field">

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

field.addEventListener("keydown", function(e) {
  console.log("keydown: " + e.key + " value: " + field.value);
});

field.addEventListener("keyup", function(e) {
  console.log("keyup: " + e.key + " value: " + field.value);
});
</script>
keydown fires before the character appears. keyup fires after.
keydown: A value: (empty)
keyup: A value: A
keydown: B value: A
keyup: B value: AB
Question 10
Hard
What is logged?
<button id="btn">Click</button>

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

btn.onclick = function() {
  console.log("First");
};

btn.onclick = function() {
  console.log("Second");
};

btn.addEventListener("click", function() {
  console.log("Third");
});
</script>
onclick is a property -- setting it replaces the previous value. addEventListener adds to a list.
Second
Third
Question 11
Medium
What is the output of this scroll handler?
<script>
let scrollCount = 0;

window.addEventListener("scroll", function() {
  scrollCount++;
});

setTimeout(function() {
  console.log("Scroll events fired: " + scrollCount);
}, 5000);
</script>

Assume the user scrolls continuously for 5 seconds.

The scroll event fires many times per second during scrolling.
A large number, typically in the hundreds (e.g., "Scroll events fired: 200+"). The exact number depends on how fast and how much the user scrolls.
Question 12
Hard
What happens?
<form id="form">
  <input type="text" id="name" required>
  <button type="submit">Submit</button>
</form>

<script>
document.getElementById("form").addEventListener("submit", function(e) {
  e.preventDefault();
  const name = document.getElementById("name");
  if (name.value.trim() === "") {
    name.style.borderColor = "red";
    name.focus();
  } else {
    name.style.borderColor = "green";
    console.log("Submitted: " + name.value);
  }
});
</script>

The user clicks Submit with an empty input, then types 'Aarav' and submits again.

First submit: empty check triggers. Second submit: name has a value.
First submit: the input border turns red and the input gains focus. Second submit: the input border turns green and "Submitted: Aarav" is logged.

Multiple Choice Questions

MCQ 1
Which method is used to attach an event handler to an element?
  • A. element.onEvent()
  • B. element.addEventListener()
  • C. element.attachEvent()
  • D. element.listenFor()
Answer: B
B is correct. addEventListener is the standard method for attaching event handlers. Option C is an old IE-only method. Options A and D do not exist.
MCQ 2
Which event fires when a user clicks a button?
  • A. press
  • B. tap
  • C. click
  • D. activate
Answer: C
C is correct. The click event fires when an element is clicked (mouse or touch). Options A, B, and D are not standard DOM events.
MCQ 3
What does e.preventDefault() do?
  • A. Stops all JavaScript on the page
  • B. Removes the event listener
  • C. Stops the browser's default action for that event
  • D. Prevents the event from being created
Answer: C
C is correct. e.preventDefault() stops default behaviors like form submission page reload, link navigation, or browser shortcuts. It does not stop JavaScript or remove listeners.
MCQ 4
Which property of the event object tells you which element was clicked?
  • A. e.element
  • B. e.source
  • C. e.target
  • D. e.origin
Answer: C
C is correct. e.target references the element that triggered the event. Options A, B, and D are not properties of DOM events.
MCQ 5
Which event fires on every keystroke in a text input?
  • A. change
  • B. input
  • C. submit
  • D. keypress
Answer: B
B is correct. The input event fires on every change to the value (keystroke, paste, delete). change fires only when the element loses focus. keypress is deprecated.
MCQ 6
What is event bubbling?
  • A. Events fire from parent to child
  • B. Events fire from child to parent through the DOM tree
  • C. Events fire only on the clicked element
  • D. Events fire on all elements simultaneously
Answer: B
B is correct. When an event fires on a child element, it bubbles up through all ancestors (parent, grandparent, etc.). A click on a button inside a div also fires click handlers on the div, body, and document.
MCQ 7
Which method stops an event from bubbling to parent elements?
  • A. e.preventDefault()
  • B. e.stopBubbling()
  • C. e.stopPropagation()
  • D. e.cancelBubble()
Answer: C
C is correct. e.stopPropagation() prevents the event from bubbling up to parent elements. e.preventDefault() stops the default browser action but does not stop bubbling.
MCQ 8
Why can you NOT remove an anonymous function event listener?
  • A. Anonymous functions are faster and cannot be stopped
  • B. Each anonymous function creates a unique object; removeEventListener needs the same reference
  • C. Anonymous functions do not support removeEventListener
  • D. You can remove them; there is no issue
Answer: B
B is correct. Two identical-looking anonymous functions are different objects in memory. removeEventListener compares by reference, not by code content. You must store the function in a variable to remove it later.
MCQ 9
Which keyboard event is deprecated and should NOT be used?
  • A. keydown
  • B. keyup
  • C. keypress
  • D. keyinput
Answer: C
C is correct. keypress is deprecated. It only fires for keys that produce characters and does not fire for Escape, arrow keys, Ctrl, etc. Use keydown or keyup instead.
MCQ 10
What does e.target.closest('li') do in event delegation?
  • A. Selects the first li on the page
  • B. Finds the nearest li ancestor of the clicked element
  • C. Selects the closest sibling li
  • D. Returns null always
Answer: B
B is correct. closest('li') traverses up the DOM tree from the clicked element and returns the first ancestor (or self) that matches the selector. This is essential for reliable event delegation with nested elements.
MCQ 11
What is the value of this inside an arrow function event handler?
  • A. The element the listener is attached to
  • B. The event object
  • C. The outer scope's this (usually window)
  • D. undefined
Answer: C
C is correct. Arrow functions do not have their own this. They inherit this from the enclosing scope. In a top-level script, that is window. If you need this to be the element, use a regular function.
MCQ 12
Which fires first: DOMContentLoaded or load?
  • A. load fires first
  • B. DOMContentLoaded fires first
  • C. They fire at the same time
  • D. It depends on the browser
Answer: B
B is correct. DOMContentLoaded fires when the HTML is fully parsed (DOM tree built). load fires after everything including images, stylesheets, and iframes have finished loading. DOMContentLoaded is always first.
MCQ 13
What does { once: true } do as a third argument to addEventListener?
  • A. Makes the listener fire only one time, then automatically removes itself
  • B. Ensures only one listener can be added
  • C. Fires the event immediately once
  • D. It is not a valid option
Answer: A
A is correct. element.addEventListener('click', handler, { once: true }) runs the handler once and then automatically removes the listener. This is useful for one-time actions like welcome modals or first-click tutorials.
MCQ 14
In the event flow, what are the three phases?
  • A. Start, middle, end
  • B. Capture, target, bubble
  • C. Create, dispatch, destroy
  • D. Attach, fire, detach
Answer: B
B is correct. Events travel in three phases: (1) Capture phase (from document down to the target), (2) Target phase (on the target element), (3) Bubble phase (from target back up to document). By default, listeners run during the bubble phase.
MCQ 15
What does e.key return when the Enter key is pressed?
  • A. 13
  • B. "enter"
  • C. "Enter"
  • D. true
Answer: C
C is correct. e.key returns the string "Enter" (capital E). Other examples: "Escape", "ArrowUp", "a", "Shift". The old e.keyCode (which returns 13) is deprecated.
MCQ 16
What is the difference between mouseenter and mouseover?
  • A. They are identical
  • B. mouseenter does not bubble; mouseover bubbles to child elements
  • C. mouseenter is faster
  • D. mouseover only works on div elements
Answer: B
B is correct. mouseover bubbles, which means it fires again when the mouse moves over child elements. mouseenter does not bubble, so it fires only once when entering the element. mouseenter/mouseleave are usually preferred for hover effects.
MCQ 17
What happens if you call addEventListener with the same function on the same event twice?
  • A. The handler runs twice per event
  • B. The second call is ignored (duplicate handlers are not added)
  • C. An error is thrown
  • D. The first handler is replaced
Answer: B
B is correct. If you pass the exact same function reference for the same event type on the same element, the browser ignores the duplicate. The handler runs only once per event.
MCQ 18
What is the difference between onclick property and addEventListener('click', ...)?
  • A. They are identical
  • B. onclick can only have one handler (last one wins); addEventListener can have multiple
  • C. addEventListener only works for click events
  • D. onclick is faster
Answer: B
B is correct. Setting element.onclick = fn replaces any previous onclick handler. addEventListener adds handlers to a list, so multiple handlers can coexist for the same event.
MCQ 19
Which event fires when the user selects an option from a <select> dropdown?
  • A. click
  • B. input
  • C. change
  • D. select
Answer: C
C is correct. The change event fires when the user selects a different option in a select dropdown. The input event also fires on select elements in modern browsers, but change is the standard and most reliable.
MCQ 20
What does e.target.closest('li') return if the click was on a span inside a div (not inside any li)?
  • A. The span element
  • B. The div element
  • C. null
  • D. An error is thrown
Answer: C
C is correct. closest('li') traverses up from the clicked element looking for an li ancestor. If none is found (the element is not inside an li), it returns null. Always check for null before using the result.

Coding Challenges

Challenge 1: Live Character Counter for Textarea

Easy
Create a textarea with a maximum of 150 characters. Show a live counter below it that says 'X / 150 characters'. Change the counter color to red when over 150.
Sample Input
Type in the textarea
Sample Output
Counter updates: '45 / 150 characters'. Turns red at 151+.
Use the input event. Use classList.add/remove for the red color, not inline styles.
<!DOCTYPE html>
<html>
<head>
  <style>
    .over-limit { color: red; font-weight: bold; }
  </style>
</head>
<body>
  <textarea id="text" rows="4" cols="40"></textarea>
  <p id="counter">0 / 150 characters</p>
  <script>
    const text = document.getElementById("text");
    const counter = document.getElementById("counter");
    text.addEventListener("input", function() {
      const len = text.value.length;
      counter.textContent = len + " / 150 characters";
      if (len > 150) {
        counter.classList.add("over-limit");
      } else {
        counter.classList.remove("over-limit");
      }
    });
  </script>
</body>
</html>

Challenge 2: Keyboard Navigation

Easy
Create a colored box (div) on the page. Use keydown events to move it: Arrow keys move it 20px in the corresponding direction. Display the current position (x, y) below the box.
Sample Input
Press arrow keys
Sample Output
The box moves around the page. Position display: 'x: 100, y: 60'.
Use keydown on the document. Use element.style.left and element.style.top. Use position: absolute on the box.
<!DOCTYPE html>
<html>
<head>
  <style>
    #box { width: 50px; height: 50px; background: #a855f7; position: absolute; top: 100px; left: 100px; border-radius: 8px; }
  </style>
</head>
<body>
  <p id="pos">x: 100, y: 100</p>
  <div id="box"></div>
  <script>
    const box = document.getElementById("box");
    const pos = document.getElementById("pos");
    let x = 100, y = 100;
    document.addEventListener("keydown", function(e) {
      if (e.key === "ArrowUp") y -= 20;
      if (e.key === "ArrowDown") y += 20;
      if (e.key === "ArrowLeft") x -= 20;
      if (e.key === "ArrowRight") x += 20;
      box.style.left = x + "px";
      box.style.top = y + "px";
      pos.textContent = "x: " + x + ", y: " + y;
    });
  </script>
</body>
</html>

Challenge 3: Color Picker with Delegation

Medium
Create a grid of 9 colored divs (3x3) using different background colors. Use event delegation on the parent container. When any color div is clicked, change the page body background to that color. Show the selected color code in a paragraph.
Sample Input
Click any color square
Sample Output
Body background changes to the clicked color. Display shows '#a855f7'.
Use a single event listener on the parent (event delegation). Store colors in data-color attributes.
<!DOCTYPE html>
<html>
<head>
  <style>
    .grid { display: grid; grid-template-columns: repeat(3, 80px); gap: 8px; }
    .color-box { width: 80px; height: 80px; border-radius: 8px; cursor: pointer; border: 3px solid transparent; }
    .color-box:hover { border-color: #000; }
    body { transition: background-color 0.3s; padding: 20px; font-family: Arial; }
  </style>
</head>
<body>
  <h2>Pick a Color</h2>
  <div class="grid" id="grid">
    <div class="color-box" data-color="#a855f7" style="background:#a855f7"></div>
    <div class="color-box" data-color="#06b6d4" style="background:#06b6d4"></div>
    <div class="color-box" data-color="#f59e0b" style="background:#f59e0b"></div>
    <div class="color-box" data-color="#ef4444" style="background:#ef4444"></div>
    <div class="color-box" data-color="#10b981" style="background:#10b981"></div>
    <div class="color-box" data-color="#3b82f6" style="background:#3b82f6"></div>
    <div class="color-box" data-color="#ec4899" style="background:#ec4899"></div>
    <div class="color-box" data-color="#8b5cf6" style="background:#8b5cf6"></div>
    <div class="color-box" data-color="#14b8a6" style="background:#14b8a6"></div>
  </div>
  <p id="selected">No color selected</p>
  <script>
    document.getElementById("grid").addEventListener("click", function(e) {
      if (e.target.classList.contains("color-box")) {
        const color = e.target.getAttribute("data-color");
        document.body.style.backgroundColor = color;
        document.getElementById("selected").textContent = "Selected: " + color;
      }
    });
  </script>
</body>
</html>

Challenge 4: Interactive Quiz with Score

Medium
Create a simple quiz with 3 multiple-choice questions. Each question has 4 radio button options. A 'Check Answers' button at the bottom checks all answers, highlights correct ones in green and wrong ones in red, and shows the score (e.g., '2 / 3').
Sample Input
Select answers and click 'Check Answers'
Sample Output
Correct answers highlighted green, wrong ones red. Score: '2 / 3'.
Use the submit event with preventDefault. Use querySelectorAll to check radio button values. Use classList for green/red highlighting.
<!DOCTYPE html>
<html>
<head>
  <style>
    .correct { background: #d1fae5; padding: 8px; border-radius: 4px; }
    .wrong { background: #fecaca; padding: 8px; border-radius: 4px; }
    .question { margin: 16px 0; padding: 12px; border: 1px solid #ddd; border-radius: 8px; }
    button { padding: 10px 20px; background: #a855f7; color: white; border: none; border-radius: 6px; cursor: pointer; }
  </style>
</head>
<body>
  <h2>Quick Quiz</h2>
  <form id="quiz">
    <div class="question" id="q1">
      <p>1. What does DOM stand for?</p>
      <label><input type="radio" name="q1" value="a"> Document Object Model</label><br>
      <label><input type="radio" name="q1" value="b"> Data Object Method</label><br>
      <label><input type="radio" name="q1" value="c"> Digital Output Machine</label>
    </div>
    <div class="question" id="q2">
      <p>2. Which event fires on every keystroke?</p>
      <label><input type="radio" name="q2" value="a"> change</label><br>
      <label><input type="radio" name="q2" value="b"> input</label><br>
      <label><input type="radio" name="q2" value="c"> submit</label>
    </div>
    <div class="question" id="q3">
      <p>3. What does e.preventDefault() do?</p>
      <label><input type="radio" name="q3" value="a"> Stops JavaScript</label><br>
      <label><input type="radio" name="q3" value="b"> Removes the element</label><br>
      <label><input type="radio" name="q3" value="c"> Stops the default browser action</label>
    </div>
    <button type="submit">Check Answers</button>
  </form>
  <p id="score"></p>
  <script>
    const answers = { q1: "a", q2: "b", q3: "c" };
    document.getElementById("quiz").addEventListener("submit", function(e) {
      e.preventDefault();
      let score = 0;
      for (const q in answers) {
        const div = document.getElementById(q);
        const selected = document.querySelector('input[name="' + q + '"]:checked');
        div.classList.remove("correct", "wrong");
        if (selected && selected.value === answers[q]) {
          div.classList.add("correct");
          score++;
        } else {
          div.classList.add("wrong");
        }
      }
      document.getElementById("score").textContent = "Score: " + score + " / 3";
    });
  </script>
</body>
</html>

Challenge 5: Double Click to Edit

Hard
Create a list of 5 items. When an item is double-clicked, it turns into an editable text input with the current text. When the user presses Enter or clicks outside (blur), the input is replaced back with the updated text. Use event delegation for the double-click.
Sample Input
Double-click 'Read a book', change to 'Read two books', press Enter
Sample Output
The list item text changes from 'Read a book' to 'Read two books'.
Use event delegation (single listener on the ul). Use dblclick event. Use keydown for Enter detection. Use blur for click-outside.
<!DOCTYPE html>
<html>
<head>
  <style>
    li { padding: 10px; cursor: pointer; font-size: 18px; border-bottom: 1px solid #eee; }
    li:hover { background: #f3f4f6; }
    input.edit { font-size: 18px; padding: 8px; width: 100%; border: 2px solid #a855f7; border-radius: 4px; }
  </style>
</head>
<body>
  <h2>Double-Click to Edit</h2>
  <ul id="list">
    <li>Complete homework</li>
    <li>Practice coding</li>
    <li>Read a book</li>
    <li>Go for a walk</li>
    <li>Call a friend</li>
  </ul>
  <script>
    document.getElementById("list").addEventListener("dblclick", function(e) {
      if (e.target.tagName === "LI") {
        const li = e.target;
        const oldText = li.textContent;
        const input = document.createElement("input");
        input.className = "edit";
        input.value = oldText;
        li.textContent = "";
        li.appendChild(input);
        input.focus();
        function save() {
          li.textContent = input.value || oldText;
        }
        input.addEventListener("blur", save);
        input.addEventListener("keydown", function(ev) {
          if (ev.key === "Enter") { input.blur(); }
          if (ev.key === "Escape") { input.value = oldText; input.blur(); }
        });
      }
    });
  </script>
</body>
</html>

Challenge 6: Keyboard Shortcuts Panel

Hard
Build a page with a content area and a shortcuts panel. Implement these keyboard shortcuts: Ctrl+B toggles bold on the content, Ctrl+I toggles italic, Ctrl+L toggles a 'large' class (bigger font), Escape hides the shortcuts panel, and 'H' (without Ctrl) toggles the panel visibility. Show which shortcut was last used.
Sample Input
Press Ctrl+B, then Ctrl+I, then Escape
Sample Output
Content becomes bold, then bold+italic. Panel hides on Escape.
Use keydown on document. Use e.preventDefault() to override browser shortcuts. Use classList.toggle for all styling.
<!DOCTYPE html>
<html>
<head>
  <style>
    body { font-family: Arial; padding: 20px; }
    #content { padding: 20px; border: 1px solid #ddd; border-radius: 8px; min-height: 100px; }
    #content.bold { font-weight: bold; }
    #content.italic { font-style: italic; }
    #content.large { font-size: 24px; }
    #panel { margin-top: 16px; padding: 16px; background: #f3f4f6; border-radius: 8px; }
    #panel.hidden { display: none; }
    .shortcut { font-family: monospace; background: #e5e7eb; padding: 2px 6px; border-radius: 4px; }
  </style>
</head>
<body>
  <div id="content">This is the editable content area. Use keyboard shortcuts to style it.</div>
  <div id="panel">
    <h3>Shortcuts</h3>
    <p><span class="shortcut">Ctrl+B</span> Bold | <span class="shortcut">Ctrl+I</span> Italic | <span class="shortcut">Ctrl+L</span> Large | <span class="shortcut">Esc</span> Hide panel | <span class="shortcut">H</span> Toggle panel</p>
  </div>
  <p id="last">Last shortcut: none</p>
  <script>
    const content = document.getElementById("content");
    const panel = document.getElementById("panel");
    const last = document.getElementById("last");
    document.addEventListener("keydown", function(e) {
      if (e.ctrlKey && e.key === "b") { e.preventDefault(); content.classList.toggle("bold"); last.textContent = "Last shortcut: Ctrl+B"; }
      else if (e.ctrlKey && e.key === "i") { e.preventDefault(); content.classList.toggle("italic"); last.textContent = "Last shortcut: Ctrl+I"; }
      else if (e.ctrlKey && e.key === "l") { e.preventDefault(); content.classList.toggle("large"); last.textContent = "Last shortcut: Ctrl+L"; }
      else if (e.key === "Escape") { panel.classList.add("hidden"); last.textContent = "Last shortcut: Escape"; }
      else if (e.key === "h" || e.key === "H") { if (!e.ctrlKey) { panel.classList.toggle("hidden"); last.textContent = "Last shortcut: H"; } }
    });
  </script>
</body>
</html>

Challenge 7: Stopwatch with Start/Stop/Reset

Hard
Build a stopwatch with a time display (MM:SS:ms format) and three buttons: Start, Stop, Reset. Start begins counting, Stop pauses it, Reset sets it back to 00:00:00. Also add a Lap button that records the current time and displays it in a list below.
Sample Input
Click Start, wait, click Lap, click Stop, click Reset
Sample Output
Timer counts up. Lap times are recorded. Stop pauses. Reset clears.
Use setInterval for the timer. Use click events for buttons. Use createElement to add lap times to a list.
<!DOCTYPE html>
<html>
<head>
  <style>
    body { font-family: Arial; padding: 20px; text-align: center; }
    #display { font-size: 48px; font-family: monospace; margin: 20px; }
    button { padding: 10px 20px; margin: 4px; border: none; border-radius: 6px; cursor: pointer; font-size: 16px; color: white; }
    #start { background: #10b981; } #stop { background: #ef4444; }
    #reset { background: #6b7280; } #lap { background: #a855f7; }
    #laps { text-align: left; max-width: 300px; margin: 20px auto; }
    #laps li { padding: 4px 0; font-family: monospace; }
  </style>
</head>
<body>
  <h2>Stopwatch</h2>
  <div id="display">00:00:00</div>
  <button id="start">Start</button>
  <button id="stop">Stop</button>
  <button id="reset">Reset</button>
  <button id="lap">Lap</button>
  <ol id="laps"></ol>
  <script>
    let ms = 0, timer = null;
    const display = document.getElementById("display");
    function format(ms) {
      const minutes = String(Math.floor(ms / 6000)).padStart(2, "0");
      const seconds = String(Math.floor((ms % 6000) / 100)).padStart(2, "0");
      const centis = String(ms % 100).padStart(2, "0");
      return minutes + ":" + seconds + ":" + centis;
    }
    document.getElementById("start").addEventListener("click", function() {
      if (!timer) { timer = setInterval(function() { ms++; display.textContent = format(ms); }, 10); }
    });
    document.getElementById("stop").addEventListener("click", function() {
      clearInterval(timer); timer = null;
    });
    document.getElementById("reset").addEventListener("click", function() {
      clearInterval(timer); timer = null; ms = 0; display.textContent = format(ms);
      document.getElementById("laps").innerHTML = "";
    });
    document.getElementById("lap").addEventListener("click", function() {
      const li = document.createElement("li");
      li.textContent = format(ms);
      document.getElementById("laps").appendChild(li);
    });
  </script>
</body>
</html>

Need to Review the Concepts?

Go back to the detailed notes for this chapter.

Read Chapter Notes

Want to learn web development with a live mentor?

Explore our Frontend Masterclass