Vocabulary for this course

The terms the chapters assume, in plain words. You can open this from any chapter.

addEventListener
A call on an element that registers a listener for one kind of event.
closest
A way to find the nearest parent of an element that matches a rule you give, starting with the element itself.
closure
A function together with the variables from the place it was written, which stay available when it runs later.
default behaviour
What the browser does on its own when an event happens, such as following a link or submitting a form, before any script intervenes.
DOM
The tree of objects a browser builds from the page, which a script can read and change while the page is open.
element
One item in the page tree, such as a heading or a button, which a script can find and change.
event
Something that happens on the page, such as a click, a key press, or a form being submitted, which a script can respond to.
event bubbling
The way an event rises from the element that received it up through each of its parents.
event target
The element that actually received the action, which may be a child of the element whose listener is running.
function
A reusable block of code that can be called with values and can return an answer to whoever called it.
handler
The function you give to a listener, which the browser runs when the event it waits for happens.
listener
A function registered on an element to wait for one kind of event and run each time that event reaches it.
property
A named value stored on an object, usually read and written with a dot, such as the text of an element.
reference
A value that points at an object rather than holding a copy, so a change made through one is visible through the other.
scope
The part of a program where a name can be used, decided by where it was declared.
variable
A name that holds a value so you can use it again; a constant cannot be pointed at a different value later.

JavaScript from the ground up

Forms and validation

Reading what a visitor typed, stopping the page from reloading, and answering with a message that helps.

Part 8 of 12

Intermediate15 min readBack to Courses

The form that reloads the page

A form submits by default: the browser gathers the fields and navigates away. That was the web’s original design, and it is exactly what a script needs to stop if it wants to answer in place.

event.preventDefault() in the submit handler cancels the navigation and leaves the page where it is. Every form-handling script starts with it, and a form that "flashes" instead of answering is almost always missing it.

That default is older than JavaScript and still useful: a form without a script submits to a URL and the server answers with a new page. Once a script takes over, the navigation is no longer wanted, but the browser cannot know that. Cancelling it is a deliberate act, which is why the call is explicit.

Read, judge, answer

const form = document.querySelector("form");
const input = document.querySelector("#email");
const message = document.querySelector(".message");

form.addEventListener("submit", (event) => {
  event.preventDefault();
  const email = input.value.trim();

  if (email.includes("@")) {
    message.textContent = `Thanks — we will write to ${email}.`;
  } else {
    message.textContent = "That does not look like an email address.";
  }
});

The value of a field

input.value is what is in the field right now, as text — even for a field that looks like a number. .trim() removes the spaces around it, because " [email protected] " is the same email with a leading space, and comparisons care.

After a successful submit, clearing the field (input.value = "") is the small courtesy that tells the visitor their input was taken. It is the difference between a form that answered and one that seems to have eaten what was typed.

Reading the field at submit time is important. A value captured when the script loaded would be the empty initial value forever, no matter what the visitor typed. The handler runs later, so it reads the current contents; that is the whole reason the read belongs inside the handler.

Validation that helps

A good message says what is wrong and what to do about it, in the same breath: "That does not look like an email — it needs an @ sign." Helpful beats formal, and specific beats polite.

Let the browser do the first pass where it can: type="email" and required in the HTML catch the common cases before the script runs. The script is for the rules HTML cannot express and for the message the visitor actually reads.

Validation the browser already knows

Long before your script runs, HTML can state some rules: required, type="email", minlength="8", min="1" and max="12". The browser checks them on submit and refuses to send an invalid form, showing its own message at the first field that fails.

form.checkValidity() runs the same checks and returns true or false without showing anything; form.reportValidity() shows the messages. A script that wants to take over the conversation can add novalidate to the form, but it is usually better to let the browser handle the simple rules and add only the checks HTML cannot express.

Every field is read in its own way

A text or number field is read with .value, and that value is always a string — even when the field has type="number". A checkbox is read with .checked, a boolean; its .value is the string "on" unless the HTML sets something else. A select is read with .value too, which is the selected option’s value.

That variety is the reason to read one field at a time and log it while building. Number(input.value) is the conversion for arithmetic, and input.value.trim() is the one for comparisons — a form is mostly text until you decide otherwise.

A worked submit, traced

Suppose the visitor types [email protected] and presses Join. The browser fires submit on the form before it navigates. The handler calls preventDefault, so the navigation is cancelled, then reads input.value, trims it and tests for an @. The test passes, and the handler writes a sentence into the message paragraph.

If the test fails, the else branch writes the other message and the field keeps its text, so the visitor can correct it without retyping. If preventDefault were missing, the browser would navigate away at the end of the handler and neither message would be on screen long enough to read.

Three mistakes: treating a number field’s .value as a number, so "5" + 1 becomes "51"; reading a checkbox with .value instead of .checked, which gives "on" whatever the box says; and forgetting event.preventDefault(), so the browser navigates away and the message you wrote disappears with the page.

Try these next

  • Log form.checkValidity() before and after filling a required field.
  • Add minlength="4" to a field and submit a shorter value to see the browser’s own message.
  • Add a checkbox, then log both its .checked and its .value to compare them.

A form that answers in place

The form reloads when it is submitted. Stop that, read the email field, and write a friendly message on the page — accepting anything with an @ in it.

Live Preview
Console output will appear here...

3 left to do

  • The form listens for submit
  • The page is stopped from reloading
  • The field’s value is read

Listen for submit on the form, call event.preventDefault(), read input.value.trim(), and set message.textContent.

An order with a checkbox

Read the number of loaves and the gluten-free checkbox, then write an order summary into the paragraph. Treat the number field as text until you convert it.

Live Preview
Console output will appear here...

3 left to do

  • The page is stopped from reloading
  • The field text is converted to a number
  • The checkbox is read with checked

Number(document.querySelector("#loaves").value) gives you a number; document.querySelector("#gluten").checked is a boolean. Build the sentence with a template literal and set the paragraph’s textContent.

Write the message for the person, not the developer: say what to change, not which check failed. “Add an @ to the address” is a fix; “invalid input” is a shrug.

Check what you learned

One question at a time. A wrong answer explains itself — take another go.

Part 1 of 5

What happens when a submit handler does not call preventDefault()?