Events: reacting to clicks and typing
Changing the page when it loads is nice. Changing it when a visitor does something is what makes a page feel alive. Every click, key press, scroll and form submission creates an event, and JavaScript can listen for them.
Listening for a click
You react to events with addEventListener. It takes the name of the event and a function to run when it happens:
<button id="greet-button" type="button">Say hello</button>
const button = document.querySelector('#greet-button');
button.addEventListener('click', () => {
console.log('Hello!');
});Click the button and the message appears in the console. The function you pass in is called an event handler. It doesn't run when the page loads. It waits until the event happens, and then it runs every time it does.
Notice that we pass the function itself, not the result of calling it. There are no parentheses after the arrow function. That's a common mix-up: writing addEventListener('click', doSomething()) runs doSomething immediately, once, instead of on each click. Write addEventListener('click', doSomething) without the parentheses.
When does the function passed to addEventListener('click', ...) run?
Select one answer
A dark mode toggle
Let's build something real. Combine a click event with classList.toggle from the last lesson:
<button id="theme-toggle" type="button">Toggle dark mode</button>
const toggle = document.querySelector('#theme-toggle');
toggle.addEventListener('click', () => {
document.body.classList.toggle('dark');
});body.dark {
--color-text: #f2f2f2;
--color-background: #1b1b1f;
}Because your colors are CSS variables, switching a single class on the body changes the whole page. That's the payoff for setting up variables in the CSS course.
Reacting to typing
The input event fires every time the content of a field changes. You read the current value with .value:
<label for="name-input">Your name</label> <input id="name-input" type="text"> <p id="greeting"></p>
const nameInput = document.querySelector('#name-input');
const greeting = document.querySelector('#greeting');
nameInput.addEventListener('input', () => {
greeting.textContent = `Hello, ${nameInput.value}!`;
});Type in the field and the greeting updates with every letter. Remember, .value is always a string, even in a number field. Use Number() if you need to do math with it.
Handling a form
Forms have a submit event that fires when someone clicks the submit button or presses enter in a field. But by default, submitting a form reloads the page, which wipes out anything your JavaScript did. To stop that, call preventDefault() on the event:
const form = document.querySelector('#contact-form');
form.addEventListener('submit', (event) => {
event.preventDefault();
const email = form.querySelector('#email').value;
console.log(`Thanks! We'll write to ${email}`);
});The event parameter is an object with information about what happened. Every event handler gets one, even if you don't always need it.
Listen for submit on the form, not click on the button. That way it also works when someone presses enter, and the browser still checks your required fields before your code runs.
Why do you call event.preventDefault() in a submit handler?
Select one answer
Other useful events
There are lots of events. A few you'll meet often:
clickwhen something is clicked or tappedinputwhen a field's value changessubmitwhen a form is sentkeydownwhen a key is pressed.event.keytells you which oneDOMContentLoadedwhen the page has finished loading, thoughdeferusually means you don't need it
Events and accessibility
Remember the rule from the HTML course: if it does something, use a button. Click events on a button also work with the keyboard. Press Tab to reach it and Enter or Space to click it, all for free. A div with a click listener doesn't do that, so keyboard users can't use it.
Which event fires every time someone types a letter in a text field?
Select one answer
Make your website interactive:
- Add a dark mode toggle button to your header and make it toggle a
darkclass on thebody, with dark colors in your CSS - Add a
submithandler to your contact form that callspreventDefault()and replaces the form with a thank you message usingtextContent - Bonus: add a character counter under your message
textareathat updates on theinputevent, like "42 characters"
Test everything with the keyboard too. Commit when it works.