Listening for what users do — clicks, keystrokes, and form actions — and writing clear, organized JavaScript that responds
Every interactive website responds to something a user does. A button is clicked. A key is pressed. A form is submitted. A mouse moves across an element. These moments are called events, and JavaScript's ability to listen for them and respond to them is what transforms a static page into a living interface.
In Chapter 20, you wrote functions. In this chapter, you will connect those functions to user actions. You will learn how to set up event listeners, how to respond to clicks and inputs, how to work with the event object, how to prevent default browser behavior, and how to give users clear feedback. You will also learn how to find and fix the most common event-related bugs. By the end of this chapter, you will be able to build pages that genuinely respond to what users do — not through tricks, but through clear, organized, readable code.
A button on a page does nothing by itself — it is just a labeled box until something tells the browser what to do when it is pressed. A text field collects keystrokes, but nothing happens with them unless code is listening. How does JavaScript know when a user has acted, and how does it decide what to do next? The answer is a three-step pattern that runs underneath nearly every interactive feature on the web: listen, detect, respond. By the end of this chapter, you will understand that pattern well enough to build your own interactive pages from scratch.
By the end of this chapter, you should be able to:
addEventListener to attach a handler function to an element's event.type attribute to control button behavior inside and outside forms.event.target and event.key.event.preventDefault() to intercept link navigation and form submission appropriately.aria-live.When you use a website, you are constantly doing things. You click buttons. You type into fields. You scroll down a page. You move your mouse over images. You press Enter to submit a search. You tab from one form field to the next.
Each of these actions is an event — a signal that something happened in the browser. JavaScript can listen for these events and run code in response to them. This is the fundamental model of interactive web pages: something happens, JavaScript notices, JavaScript reacts.
Beginners sometimes think of events as only button clicks. Events are much broader than that. Here is a sample of the kinds of events browsers can detect:
| Category | Examples |
|---|---|
| Mouse | click, dblclick, mouseenter, mouseleave, mouseover |
| Keyboard | keydown, keyup, keypress |
| Form | submit, input, change, focus, blur |
| Document | DOMContentLoaded, scroll, resize |
| Touch | touchstart, touchend |
You do not need to memorize all of these right now. What matters at this stage is understanding that events are happening constantly as users interact with the page, and JavaScript can respond to them.
JavaScript's interaction model follows a simple three-step pattern:
1. Listen — Tell JavaScript which element to watch, and which event to watch for.
2. Detect — The browser notices when that event happens on that element.
3. Respond — JavaScript runs a function you wrote to handle it.
This pattern is the foundation of all JavaScript interactivity. Everything in this chapter follows this model.
Events happen on specific HTML elements. A click event on a button is different from a click event on a paragraph. An input event on a text field is different from an input event on a checkbox. When you set up an event listener, you always attach it to a specific element on the page.
To respond to an event, you need to set up an event listener. An event listener is an instruction you give to a specific element: "When this event happens on you, run this function."
The standard way to set up an event listener in modern JavaScript is the addEventListener method.
element.addEventListener(eventType, handlerFunction);
element is the HTML element you want to watch. You get this using document.querySelector() or a similar method.eventType is a string describing the event you want to listen for, such as 'click', 'input', or 'submit'.handlerFunction is the function you want to run when the event happens.Here is the simplest possible event listener. It watches a button for a click, and when the click happens, it runs a function.
<button id="greet-button">Say Hello</button>
const greetButton = document.querySelector('#greet-button');
greetButton.addEventListener('click', function () {
console.log('Hello!');
});
When the user clicks the button, the console displays: Hello!
Walk through this line by line:
document.querySelector('#greet-button') finds the button element in the page.greetButton.addEventListener('click', ...) tells the button to listen for a click event.In the example above, the function has no name — it is defined directly inside addEventListener. This is called an anonymous function. It works fine for simple cases. You can also define the function separately and pass it by name, which is often cleaner and easier to read as your code grows.
function sayHello() {
console.log('Hello!');
}
const greetButton = document.querySelector('#greet-button');
greetButton.addEventListener('click', sayHello);
Notice: when you pass a function by name to addEventListener, you write sayHello, not sayHello(). The parentheses would call the function immediately. Without the parentheses, you are passing the function itself to be called later.
Writing addEventListener('click', sayHello()) calls sayHello immediately when the page loads, not when the button is clicked. Leave off the parentheses when passing functions to addEventListener.
You can attach more than one event listener to the same element. Each listener is independent.
const button = document.querySelector('#my-button');
button.addEventListener('click', function () {
console.log('Listener one ran.');
});
button.addEventListener('click', function () {
console.log('Listener two ran.');
});
Both functions will run when the button is clicked, in the order they were added.
You can also remove an event listener using removeEventListener. This requires using a named function — anonymous functions cannot be removed because there is no way to reference them again later. Removing event listeners is an advanced topic, but it is good to know that it is possible.
The click event is the most common event in web development. Every button, link, card, toggle, and interactive element on the web relies on click events in some form.
<button id="launch-button">Launch</button>
<p id="status">Status: waiting.</p>
const launchButton = document.querySelector('#launch-button');
const statusText = document.querySelector('#status');
launchButton.addEventListener('click', function () {
statusText.textContent = 'Status: launched!';
});
When the user clicks the button, the paragraph text changes from "Status: waiting." to "Status: launched!" This example combines two skills: event listening from this chapter, and DOM updates from Chapter 22. (You are previewing Chapter 22's content here — updating the page is covered in full detail there.)
Although buttons are the most natural targets for clicks, addEventListener can be attached to almost any HTML element: a paragraph, a heading, a list item, a card, an image.
const card = document.querySelector('.product-card');
card.addEventListener('click', function () {
console.log('Card was clicked.');
});
Interactive actions should normally happen on elements that users expect to be interactive — buttons, links, and labeled controls. Putting click listeners on arbitrary div elements can create accessibility problems because screen readers and keyboard users will not know those elements are interactive.
The dblclick event fires when a user clicks an element twice in rapid succession.
document.querySelector('#edit-field').addEventListener('dblclick', function () {
console.log('Double-clicked — entering edit mode.');
});
Use double-click sparingly. Many users, especially on touch devices, do not double-click intuitively.
Buttons are the primary interactive control on web pages. Understanding how buttons work — and how to attach behavior to them — is a core skill.
A <button> element is meant for triggering actions. It is distinct from a link (<a>), which is meant for navigation.
| Element | Use for |
|---|---|
<button> | Actions (submit, toggle, run something) |
<a> | Navigation (go somewhere) |
Using a button for an action and a link for navigation is correct semantically and also benefits screen reader users, who can distinguish between the two.
HTML buttons have a type attribute with three possible values:
type="button" — A general-purpose button. Does not submit forms. This is usually what you want when attaching a click listener.type="submit" — Submits the nearest form. This is the default if you do not specify a type inside a form.type="reset" — Clears the form.Always specify type="button" on buttons that are not meant to submit a form. If you place a button inside a <form> without specifying its type, the browser may treat it as a submit button and reload the page when clicked.
<button type="button" id="toggle-button">Show Details</button>
A common pattern is to toggle a button between two states. Here is a simple version:
<button type="button" id="toggle-button">Show Details</button>
<div id="details" style="display: none;">
<p>Here are the hidden details.</p>
</div>
const toggleButton = document.querySelector('#toggle-button');
const details = document.querySelector('#details');
let detailsVisible = false;
toggleButton.addEventListener('click', function () {
if (detailsVisible) {
details.style.display = 'none';
toggleButton.textContent = 'Show Details';
detailsVisible = false;
} else {
details.style.display = 'block';
toggleButton.textContent = 'Hide Details';
detailsVisible = true;
}
});
This example introduces the if/else pattern you studied in Chapter 23 (which follows this chapter). For now, read it as: "if the details are visible, hide them; otherwise, show them."
Setting style.display directly works but mixes JavaScript with visual control. A cleaner pattern — toggling CSS classes instead — is covered in Chapter 22.
You can prevent a button from being clicked by setting its disabled property to true.
const submitButton = document.querySelector('#submit-button');
submitButton.disabled = true;
A disabled button is grayed out in most browsers and cannot be clicked. Enabling it again:
submitButton.disabled = false;
Disabling a button after a user submits a form is a useful technique to prevent duplicate submissions.
While click events respond to button presses and other single-action interactions, input events respond to users typing, selecting, or modifying form controls.
The input event fires every time the value of a form field changes. For a text input, this means it fires on every keystroke.
<input type="text" id="name-field" placeholder="Enter your name">
<p id="greeting-output">Hello, stranger.</p>
const nameField = document.querySelector('#name-field');
const greetingOutput = document.querySelector('#greeting-output');
nameField.addEventListener('input', function () {
const currentValue = nameField.value;
if (currentValue.trim() === '') {
greetingOutput.textContent = 'Hello, stranger.';
} else {
greetingOutput.textContent = 'Hello, ' + currentValue + '!';
}
});
As the user types into the text field, the paragraph updates in real time.
nameField.value retrieves the current text in the input..trim() removes leading and trailing spaces, so an input of only spaces is treated as empty.The .value property works for most form fields:
const emailField = document.querySelector('#email');
const currentEmail = emailField.value;
console.log(currentEmail);
For checkboxes, use .checked instead of .value:
const agreeCheckbox = document.querySelector('#agree');
const isChecked = agreeCheckbox.checked; // true or false
For a group of radio buttons, you need to find the one that is currently selected. That is covered in Chapter 24 on forms.
The change event is similar to input, but it fires only when the user finishes making a change and moves away (blurs) from the field. For text inputs, change fires when the user clicks elsewhere or presses Tab. For checkboxes and select menus, change fires immediately when the state changes.
const colorSelect = document.querySelector('#color-select');
colorSelect.addEventListener('change', function () {
console.log('Selected color: ' + colorSelect.value);
});
Use input when you want to react on every keystroke (live feedback). Use change when you want to react only after the user finishes.
focus fires when a form element receives focus — when the user clicks into it or tabs to it. blur fires when a form element loses focus — when the user clicks elsewhere or tabs away. These events are useful for showing a helper message when a field is active, validating a field when the user leaves it, or highlighting an active field visually.
const emailField = document.querySelector('#email');
emailField.addEventListener('focus', function () {
console.log('Email field is active.');
});
emailField.addEventListener('blur', function () {
console.log('Email field lost focus.');
});
An event handler function is the function that runs in response to an event. You have been writing them throughout this chapter. Now it is time to think more carefully about how to write them well.
A good event handler function does one clear thing. If a click should validate a form, update the page, and log a message, write separate functions for each task and call them from the handler.
function validateForm() {
// validation logic
}
function updatePage() {
// page update logic
}
submitButton.addEventListener('click', function () {
validateForm();
updatePage();
});
This is more readable and easier to debug than putting all the logic directly inside the anonymous function.
Rather than writing anonymous functions everywhere, you can name your handler functions clearly.
function handleSubmitClick() {
validateForm();
updatePage();
}
submitButton.addEventListener('click', handleSubmitClick);
Now when you read the event listener line, it is immediately clear what happens when the button is clicked.
Because event handlers are regular functions, you can attach the same handler to multiple elements.
<button type="button" class="close-button">Close</button>
<button type="button" class="close-button">Close</button>
<button type="button" class="close-button">Close</button>
function handleClose() {
console.log('A close button was clicked.');
}
const closeButtons = document.querySelectorAll('.close-button');
closeButtons.forEach(function (button) {
button.addEventListener('click', handleClose);
});
querySelectorAll returns all matching elements. forEach loops through them and attaches the same listener to each one. You will study querySelectorAll and forEach in more detail in Chapter 22 and Chapter 23.
| Handler functions should | Handler functions should not |
|---|---|
| Be short and focused | Contain hundreds of lines of mixed logic |
| Call other functions for complex work | Directly manipulate everything on the page from one function |
| Use descriptive names | Be named function1, handler, doStuff |
| Be easy to read without comments | Require extensive comments to understand |
When JavaScript calls your event handler function, it automatically passes an argument to it. This argument is the event object — a bundle of information about the event that just happened. You do not have to use the event object, but when you need it, it is there.
To access the event object, add a parameter to your handler function. The parameter is conventionally named event or e.
document.querySelector('#my-button').addEventListener('click', function (event) {
console.log(event);
});
When you click the button and look in the console, you will see a large object printed. It contains many properties describing the event.
| Property | What it gives you |
|---|---|
event.type | The type of event as a string: 'click', 'input', etc. |
event.target | The specific element that triggered the event |
event.key | The key pressed, for keyboard events |
event.preventDefault() | A method to stop default browser behavior (covered in 21.8) |
event.target is especially useful when one function handles events from multiple elements and you need to know which specific element was clicked or changed.
<button type="button" class="color-button" data-color="red">Red</button>
<button type="button" class="color-button" data-color="blue">Blue</button>
<button type="button" class="color-button" data-color="green">Green</button>
const colorButtons = document.querySelectorAll('.color-button');
colorButtons.forEach(function (button) {
button.addEventListener('click', function (event) {
const chosenColor = event.target.dataset.color;
console.log('Chosen color: ' + chosenColor);
});
});
event.target is the specific button that was clicked. dataset.color reads the data-color attribute from that button. This pattern — storing information in data- attributes and reading it from event.target — is a very common and clean way to build interactive elements.
When listening for keyboard events, event.key tells you which key was pressed.
document.querySelector('#search-field').addEventListener('keydown', function (event) {
if (event.key === 'Enter') {
console.log('Search submitted by pressing Enter.');
}
});
event.key returns the actual key name as a string: 'Enter', 'Escape', 'ArrowUp', 'a', '1', and so on.
Some HTML elements have built-in browser behaviors that happen automatically when events occur. Links navigate to a new page when clicked. Form submit buttons reload the page or send form data. Sometimes you need to stop these default behaviors so JavaScript can handle them instead.
Calling event.preventDefault() on the event object stops the browser's default response to that event. The event still fires — your handler function still runs — but the browser's built-in behavior does not happen.
This is occasionally useful when building interactive navigation menus or single-page apps. In most cases, links should navigate as expected — only prevent navigation when you have a specific reason.
<a href="https://example.com" id="preview-link">Preview</a>
document.querySelector('#preview-link').addEventListener('click', function (event) {
event.preventDefault();
console.log('Link click intercepted — no navigation happened.');
});
The link looks and behaves like a link (including keyboard accessibility), but clicking it does not navigate away from the page.
This is one of the most important uses of event.preventDefault(). When a form is submitted, the browser's default behavior is to send the form data to a server and reload the page. If you want to handle the form with JavaScript — validate it, display a confirmation, send data with fetch() — you need to prevent that default submission.
<form id="contact-form">
<label for="name">Name:</label>
<input type="text" id="name" name="name">
<button type="submit">Submit</button>
</form>
const contactForm = document.querySelector('#contact-form');
contactForm.addEventListener('submit', function (event) {
event.preventDefault();
const nameValue = document.querySelector('#name').value;
console.log('Form submitted with name: ' + nameValue);
});
Without event.preventDefault(), the page would reload when the form is submitted. With it, JavaScript takes over and you can do whatever you want — validate the data, display a message, or send the data with fetch().
event.preventDefault() is a powerful tool, but use it only when you have a good reason. Preventing link navigation without providing an alternative makes pages unusable. Preventing form submission without replacing it with your own handling leaves users with no feedback. Always think about what the user expects to happen and ensure they still get a useful result.
Event listeners are not just about running code internally. They are also about communicating with users. When a user clicks a button, types into a field, or submits a form, they want to know something happened. Giving clear, timely, accessible feedback is a core part of building good interactive pages.
The most direct form of feedback is changing text the user can see.
<button type="button" id="save-button">Save</button>
<p id="save-status"></p>
const saveButton = document.querySelector('#save-button');
const saveStatus = document.querySelector('#save-status');
saveButton.addEventListener('click', function () {
saveStatus.textContent = 'Your work has been saved.';
});
The paragraph starts empty and fills with confirmation text when the user clicks Save.
A common feedback pattern shows a message that was previously hidden.
<button type="button" id="confirm-button">Confirm</button>
<p id="confirm-message" class="hidden">Your selection has been confirmed.</p>
.hidden {
display: none;
}
const confirmButton = document.querySelector('#confirm-button');
const confirmMessage = document.querySelector('#confirm-message');
confirmButton.addEventListener('click', function () {
confirmMessage.classList.remove('hidden');
});
Rather than setting style.display directly, this approach uses a CSS class (hidden) to control visibility, and JavaScript simply adds or removes that class. This keeps visual control in CSS and behavioral control in JavaScript, which is the clean separation you learned in Chapter 11.
Buttons can also confirm their own state by changing their text or appearance.
saveButton.addEventListener('click', function () {
saveButton.textContent = 'Saved!';
saveButton.disabled = true;
});
This makes the button confirm the save and prevents the user from clicking it again immediately.
Visual feedback is important, but so is feedback that works for all users. When you show or hide messages with JavaScript, screen readers may not automatically announce the change. Adding aria-live="polite" to a feedback element tells screen readers to announce its content when it changes, without interrupting the user.
<p id="status-message" aria-live="polite"></p>
document.querySelector('#status-message').textContent = 'Form submitted successfully.';
When the text changes, a screen reader will announce it to the user. Using aria-live="assertive" is for urgent messages that should interrupt the user immediately, such as error alerts. Use polite for most feedback.
Sometimes feedback should disappear after a few seconds. JavaScript's setTimeout function runs code after a delay.
saveButton.addEventListener('click', function () {
saveStatus.textContent = 'Saved!';
setTimeout(function () {
saveStatus.textContent = '';
}, 3000);
});
The message appears immediately, then clears after 3000 milliseconds (3 seconds). setTimeout is not an event listener — it is a browser timer — but it combines naturally with event-driven code.
Auto-disappearing messages can be missed by users who read slowly or use screen readers. Use them for supplementary feedback only, not for critical information.
Event listeners fail in predictable ways. Knowing the most common problems helps you find and fix them quickly.
If document.querySelector() does not find the element, it returns null. Calling addEventListener on null throws an error.
Cannot read properties of null (reading 'addEventListener')
Causes: the selector is wrong (a typo, wrong class name, wrong ID); the element does not exist in the HTML; or the JavaScript ran before the element was added to the page.
Fix: double-check the selector. Open the Elements panel in developer tools and confirm the element's ID or class name exactly. If the script runs before the HTML is ready, move the <script> tag to the bottom of the <body>, or use the DOMContentLoaded event (see Problem 5).
This happens when you accidentally call the function instead of passing it.
button.addEventListener('click', handleClick());
// handleClick() runs immediately
button.addEventListener('click', handleClick);
// handleClick is passed as a reference, called later
A button inside a <form> element without type="button" defaults to type="submit". When clicked, it submits the form, which reloads the page.
Fix: add type="button" to any button inside a form that is not meant to submit it. Or use event.preventDefault() on the form's submit listener.
If multiple elements share a class, querySelector returns only the first matching element. If you want all of them, use querySelectorAll and a forEach loop.
document.querySelector('.card').addEventListener('click', handleClick);
document.querySelectorAll('.card').forEach(function (card) {
card.addEventListener('click', handleClick);
});
If your script runs before the browser has finished reading the HTML, querySelector will not find elements because they do not exist yet.
<!-- All your HTML here -->
<script src="js/main.js"></script>
</body>
document.addEventListener('DOMContentLoaded', function () {
// All your event listener setup goes here
const button = document.querySelector('#my-button');
button.addEventListener('click', handleClick);
});
DOMContentLoaded fires when the browser has finished reading and processing the HTML. Any code inside this listener can safely reference any element on the page.
event.preventDefault() must be called before other code that might have side effects. If you call it after a long chain of operations, the browser's default may already have triggered.
form.addEventListener('submit', function (event) {
event.preventDefault(); // First line
// Validation and other logic follows
});
When an event listener is not working, add console.log statements inside the handler function to confirm it is running. If the message appears in the console, the listener is working and the problem is elsewhere. If it does not appear, the listener never fired — meaning either the element was not found, or the event is not happening as expected.
This worked example brings together the major skills from this chapter: attaching event listeners, responding to clicks, reading input, using the event object, giving feedback, and writing organized handler functions.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interactive Panel</title>
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<main>
<h1>Interactive Panel</h1>
<section aria-labelledby="color-heading">
<h2 id="color-heading">Choose a Color</h2>
<div class="button-group">
<button type="button" class="color-btn" data-color="Red">Red</button>
<button type="button" class="color-btn" data-color="Blue">Blue</button>
<button type="button" class="color-btn" data-color="Green">Green</button>
</div>
<p id="color-display" aria-live="polite">No color chosen yet.</p>
</section>
<section aria-labelledby="greeting-heading">
<h2 id="greeting-heading">Your Greeting</h2>
<label for="name-input">Enter your name:</label>
<input type="text" id="name-input" placeholder="Your name">
<p id="greeting-display" aria-live="polite">Hello, visitor.</p>
</section>
<section>
<button type="button" id="reset-btn">Reset Everything</button>
</section>
</main>
<script src="js/main.js"></script>
</body>
</html>
// --- Element References ---
const colorButtons = document.querySelectorAll('.color-btn');
const colorDisplay = document.querySelector('#color-display');
const nameInput = document.querySelector('#name-input');
const greetingDisplay = document.querySelector('#greeting-display');
const resetButton = document.querySelector('#reset-btn');
// --- Color Button Handlers ---
function handleColorClick(event) {
const chosenColor = event.target.dataset.color;
colorDisplay.textContent = 'You chose: ' + chosenColor;
}
colorButtons.forEach(function (button) {
button.addEventListener('click', handleColorClick);
});
// --- Name Input Handler ---
function handleNameInput() {
const name = nameInput.value.trim();
if (name === '') {
greetingDisplay.textContent = 'Hello, visitor.';
} else {
greetingDisplay.textContent = 'Hello, ' + name + '!';
}
}
nameInput.addEventListener('input', handleNameInput);
// --- Reset Handler ---
function handleReset() {
colorDisplay.textContent = 'No color chosen yet.';
nameInput.value = '';
greetingDisplay.textContent = 'Hello, visitor.';
}
resetButton.addEventListener('click', handleReset);
querySelectorAll gets all three buttons. forEach attaches the same handler to each. The handler reads event.target.dataset.color to know which button was clicked, without needing three separate functions.input event fires on every keystroke. The handler trims whitespace, checks if the input is empty, and updates the greeting accordingly.Event listeners on multiple elements with forEach; using event.target to identify which element fired the event; reading data- attributes through dataset; reading input values with .value; giving accessible feedback with aria-live; and keeping handlers named and focused.
Read each code sample carefully and answer the questions that follow.
<button type="button" id="show-btn">Show Message</button>
<p id="message" style="display: none;">Welcome to the site!</p>
const showBtn = document.querySelector('#show-btn');
const message = document.querySelector('#message');
showBtn.addEventListener('click', function () {
message.style.display = 'block';
});
type="submit" and was inside a <form>?const inputs = document.querySelectorAll('.score-input');
inputs.forEach(function (input) {
input.addEventListener('input', function () {
console.log('Score changed: ' + input.value);
});
});
input.value contain for a text input reading 87?querySelector were used instead of querySelectorAll?<form id="search-form">
<label for="query">Search:</label>
<input type="text" id="query">
<button type="submit">Go</button>
</form>
const searchForm = document.querySelector('#search-form');
searchForm.addEventListener('submit', function (event) {
event.preventDefault();
const query = document.querySelector('#query').value.trim();
if (query === '') {
console.log('Please enter a search term.');
} else {
console.log('Searching for: ' + query);
}
});
event.preventDefault() stop here?document.querySelector('#color-picker').addEventListener('change', function (event) {
const chosen = event.target.value;
document.querySelector('#preview-box').style.backgroundColor = chosen;
});
#color-picker likely to be?event.target.value hold in this context?Trace through each example carefully, predicting what will be logged to the console or displayed on the page.
<button type="button" id="btn-a">A</button>
<button type="button" id="btn-b">B</button>
let clickCount = 0;
document.querySelector('#btn-a').addEventListener('click', function () {
clickCount = clickCount + 1;
console.log('Count: ' + clickCount);
});
document.querySelector('#btn-b').addEventListener('click', function () {
clickCount = 0;
console.log('Reset. Count: ' + clickCount);
});
const field = document.querySelector('#number-field');
const output = document.querySelector('#result');
field.addEventListener('input', function () {
const val = Number(field.value);
if (val > 100) {
output.textContent = 'Too high.';
} else if (val < 0) {
output.textContent = 'Too low.';
} else {
output.textContent = 'Valid: ' + val;
}
});
output.textContent show after each step?id="toggle". A JavaScript file contains:
const btn = document.querySelector('#toggle');
btn.addEventListener('click', function () {
btn.textContent = 'Clicked!';
});
btn.addEventListener('click', function () {
btn.style.backgroundColor = 'yellow';
});
What happens the first time the user clicks the button? What happens the second time?
document.querySelector('form').addEventListener('submit', function (event) {
console.log('Handler ran.');
});
When the user submits the form, what happens? What would be different if event.preventDefault() were added?
const btn = document.querySelector('#save-btn');
btn.addEventListener('click', handleSave());
The page loads. Before the user clicks anything, what happens? What is the bug?
<button type="button" id="launchBtn">Launch</button>
const button = document.querySelector('#launch-btn');
button.addEventListener('click', function () {
console.log('Launched!');
});
Cannot read properties of null (reading 'addEventListener'). What is wrong? How do you fix it?<form id="contact">
<input type="text" id="email">
<button>Send</button>
</form>
document.querySelector('button').addEventListener('click', function () {
console.log('Button clicked.');
});
const cards = document.querySelectorAll('.card');
cards.addEventListener('click', function () {
console.log('Card clicked.');
});
cards.addEventListener is not a function. What is the problem? How do you fix it?saveButton.addEventListener('click', function () {
statusMessage.textContent = 'Saved!';
setTimeout(function () {
statusMessage.textContent = '';
}, 2000);
});
document.body.style.backgroundColor to 'lightblue'. When clicked again, change it back to '' (empty string restores the default). Use a variable to track the current state..value.length to get the character count.data-message attribute containing a different short message. When any button is clicked, display that button's message in a paragraph below the buttons. Use event.target.dataset.message to read the message from the clicked button.aria-live="polite" on the message paragraph.focus and blur events. Then refactor: instead of setting style.borderColor directly, add and remove a CSS class called input--active.Review the following code and identify any accessibility issues with the event handling and feedback.
<div id="toggle-area" onclick="toggleContent()">
Show more
</div>
<div id="extra-content" style="display: none;">
<p>Here is the hidden content.</p>
</div>
function toggleContent() {
const content = document.querySelector('#extra-content');
if (content.style.display === 'none') {
content.style.display = 'block';
} else {
content.style.display = 'none';
}
}
<div> for this interaction a problem for keyboard users?onclick attribute in HTML considered less ideal than addEventListener in JavaScript?<button>, addEventListener, and aria-live.These questions connect Chapter 21 material to earlier chapters.
<script src="js/main.js"> tag inside the <head> element of their page. The JavaScript tries to select a button and attach a click listener. The listener never fires. What is the likely cause, and what is the standard fix?<select>) with several options. Write the JavaScript to listen for the change event on the select menu and display the currently selected value in a paragraph..button and #special-button selectors. The JavaScript attaches click listeners to both. Which element does document.querySelector('#special-button') select? If the element also has the class button, will both event listeners fire when it is clicked?data-greeting attributes on the buttons. Display the greeting in a paragraph with aria-live="polite".Code requirements: use a separate HTML file, a separate CSS file, and a separate JavaScript file; use type="button" on all buttons; use addEventListener for all interactions; use named handler functions where appropriate; use aria-live="polite" on feedback paragraphs; use data- attributes where appropriate.
Add a keyboard listener so the counter can also be controlled by pressing the Up Arrow and Down Arrow keys. When the counter reaches 10, display a message: "You reached 10!" Clear the message if the count drops below 10.
Chapter 22 introduces the Document Object Model — the browser's internal representation of your HTML page as a tree of connected nodes. You have been using small pieces of the DOM throughout Chapters 19, 20, and 21 without formally studying it. Chapter 22 explains what the DOM actually is, how to select elements reliably, how to read and change text and attributes, how to add and remove classes, and how to create new elements and add them to the page. The DOM is the bridge between JavaScript and HTML. Understanding it well will make every interaction you write cleaner, more reliable, and easier to debug.