Skip to lesson content
Web Technologies › Level 17
LEVEL 17 · EVENTS

JavaScript Events and Forms

Trace browser interactions and build a clear, correctable form workflow.

⚡ Events🧭 Propagation✅ Forms + validation🧪 Labs + MCQs
01

Learning Objectives

Level 16 updated a document tree. This lesson decides when and why those updates happen. You will attach listeners, inspect an event, trace its propagation, distinguish cancellation from propagation control and handle a form’s submission deliberately.

Our running task is a local workshop-request preview. The learner supplies fictional contact details, chooses a session and requests places. The page checks input, shows field-specific errors and exposes the resulting form data locally. The purpose is to understand events and validation, not to book a real workshop.

Events

Connect meaningful native controls to their actions.

Propagation

Trace capture, target and bubble listeners.

Validation

Combine native constraints with stated task rules.

Form data

Inspect successful controls and handle submit once.

02

Events — A Signal That Something Happened

An event represents an occurrence, such as a click, an input change or a form submission. The browser dispatches an event object through the relevant targets. A listener responds to it with a function.

Choose an event for the task rather than attaching every action to a pointer gesture. A native button’s click can be activated through supported keyboard interaction. A form’s submit event supports the submission workflow beyond a particular button click.

A programmatically dispatched event is useful for a controlled test, but it does not automatically prove the browser’s full native interaction or validation behavior. Test the actual control as well as the handler.

A workshop interaction
Native control

A learner activates a button or submits the form.

Event object

The browser exposes type, targets and state.

Listener

Code reads values, validates and updates feedback.

03

addEventListener — Pass the Function

AddEventListener registers a callback for an event type. Pass the function itself, not the result of immediately calling it. A named callback is useful when you need to remove the same listener later.

Repeatedly adding distinct anonymous functions can create multiple handlers even if their bodies look identical. For a setup routine that can run more than once, guard initialization or manage listener cleanup.

HTML onclick attributes mix behavior into markup and can make maintenance harder. This lesson registers listeners in the external lesson script and keeps its native controls understandable from their HTML.

function showDetails(event) {
  console.log(event.type);
}
button.addEventListener("click", showDetails);
// Later, when this listener is no longer needed:
button.removeEventListener("click", showDetails);

RemoveEventListener needs the matching event type, callback identity and capture setting. Rewriting a visually identical arrow function does not supply the original callback object.

04

Event Object — target and currentTarget

Event.target identifies the target associated with the dispatch as exposed to the listener. CurrentTarget is the object whose listener is currently running. In our simple light-DOM example, clicking a span inside a link can make the span the target while the link remains currentTarget for its own listener.

Event.type identifies the event kind. EventPhase distinguishes capture, at-target and bubble processing. DefaultPrevented indicates whether a cancelable event’s default action has been canceled.

Read or copy currentTarget during the listener if you need it later. Its value is tied to listener invocation and is normally null after dispatch finishes. Complex cases such as shadow DOM can retarget events; this lab uses an ordinary nested light-DOM structure.

link.addEventListener("click", event => {
  const observed = {
    type: event.type,
    target: event.target.id,
    listener: event.currentTarget.id,
    phase: event.eventPhase
  };
  console.log(observed);
});

The event-path lab records these values synchronously rather than storing the event object and later assuming currentTarget still names the listener.

05

Capture, Target and Bubble

For a bubbling click, ancestor capture listeners run toward the target, target listeners run, then ancestor bubble listeners run outward. A listener registered with capture: true observes the capture side of that path.

Our playground has an outer region, an inner region and a link containing a span. Its observed listeners normally run outer capture, inner capture, link listener, inner bubble and outer bubble. If the span is clicked, the link is an ancestor of the actual target; if the link itself is the target, its own listener runs at target.

Not every event bubbles. Focus and blur differ from bubbling focusin and focusout, for example. Choose an event and inspect its propagation rules before relying on a parent listener.

outer.addEventListener("click", observe, { capture: true });
inner.addEventListener("click", observe, { capture: true });
link.addEventListener("click", observe);
inner.addEventListener("click", observe);
outer.addEventListener("click", observe);
Observed nested click path
Capture

Outer region → inner region.

Link listener

Read target and currentTarget separately.

Bubble

Inner region → outer region unless stopped.

06

preventDefault and stopPropagation

PreventDefault asks the browser to cancel an event’s default action when the event is cancelable. For a link click, that can cancel navigation. It does not automatically stop propagation to other listeners.

StopPropagation prevents further propagation beyond the current processing point. It does not by itself cancel navigation or prevent every other listener on the same node from running. StopImmediatePropagation also stops later listeners on the same node for that event.

Passive listeners cannot cancel default actions through preventDefault. Use a passive listener for suitable observation, such as a scroll-related listener that does not need to cancel interaction, rather than setting passive blindly.

link.addEventListener("click", event => {
  event.preventDefault(); // cancel navigation if cancelable
  // Ancestor bubble listeners can still run.
});

In the playground, “Cancel navigation” still records all five observed listeners. “Stop propagation” records the two capture listeners and the link listener while its local fragment navigation remains available.

07

Delegation — Listen on a Stable Parent

Delegation uses a suitable ancestor listener to handle events from its descendants. It is useful when cards are inserted after initialization because the parent listener can remain in place. It requires an event that reaches the parent and careful target checking.

Closest can find a relevant button when the click landed on a nested icon or span. Then confirm that the chosen control belongs to the intended container. This avoids letting a broadly matched button trigger an unrelated action.

Keep the action name controlled and meaningful. Delegation is a listener organization technique, not permission to execute arbitrary text from a data attribute.

list.addEventListener("click", event => {
  const button = event.target.closest("button[data-action]");
  if (!button || !list.contains(button)) return;
  if (button.dataset.action === "details") {
    showWorkshopDetails(button.dataset.id);
  }
});

A listener stopped before reaching list will not be observed by this delegation example. Inspect the actual path when a dynamically added control appears inactive.

08

Click, Keyboard and Native Semantics

Use a button for an action and a link for navigation. Native controls provide established keyboard behavior, focus handling and accessibility semantics. A clickable div requires additional work and can still behave inconsistently.

Do not add a second Enter/Space activation handler to a native button without considering its native click behavior; that can duplicate the action. A custom control needs a deliberate keyboard contract, but the default choice should be a native control.

Keydown is useful for tasks such as a documented shortcut. Preserve ordinary Tab navigation and text-entry keys unless the specific interaction requires handling them. Make the action available visibly as well as through a shortcut.

<button type="button" id="details">Show details</button>
<a href="#workshop-summary">Read workshop summary</a>

The playground link can be activated by Enter. The registration preview uses a native submit button and a form submit listener. Native browser behavior remains part of the post-deployment test.

09

input, change and Editing Feedback

Input generally reports user-driven changes as they occur. Change reports a committed change according to the control’s behavior. Text inputs, selects and checkboxes do not all commit in exactly the same way.

Assigning input.value from code does not automatically fire the input event. A program that needs a follow-up update should call its own update function or dispatch a deliberately chosen event with a clear purpose.

Keep editing feedback calm. Clear a stale field error when its value is edited, then validate again on submission. Avoid stealing focus or announcing the entire form on every keystroke.

nameInput.addEventListener("input", () => {
  nameInput.setCustomValidity("");
  nameError.textContent = "";
  nameInput.removeAttribute("aria-invalid");
});

Clearing an error means the stale message has been removed; it does not guarantee that the new entry meets every rule. The lab rechecks the complete form on its next submit attempt.

10

Forms — Names, Labels and Button Types

A label names a control for the learner; a name attribute identifies a field in submitted form data. An ID helps connect the label and scripting. Those three roles should not be confused.

Use type="submit" for the primary form action and type="button" for a local helper that should not submit. A button without an explicit type inside a form can submit unexpectedly.

Required, type, min, max and step provide native constraints. A select can have an empty required placeholder. A checked checkbox can contribute its named value; an unchecked checkbox is omitted from ordinary FormData.

<form id="request">
  <label for="places">Places requested</label>
  <input id="places" name="places" type="number"
         min="1" max="4" step="1" required>
  <button type="submit">Preview request</button>
  <button type="button">Clear messages</button>
</form>

The lab’s limits are teaching rules. Native client constraints improve feedback; a real receiving service must validate its own accepted data and business rules.

11

Handle submit on the Form

A form submit listener handles the form workflow, including supported implicit submission and requestSubmit. Listening only to a particular button’s click can miss other ways the form is submitted.

In the normal native workflow, failing interactive constraints can prevent submission before a submit event fires. The lab uses novalidate intentionally so its submit handler can show inline errors for every attempt, while still consulting native validity APIs.

PreventDefault is called immediately in the lab’s submit listener because its result is a local preview. It does not send a request or navigate to a result page. The submit button is initially disabled until the script has installed its handler.

form.addEventListener("submit", event => {
  event.preventDefault();
  // Validate fields and display a local preview.
});

One accepted click should produce one handling result. Do not duplicate the same validation in both a click listener and a submit listener when both would process the same attempt.

12

Native Validity and Custom Task Rules

CheckValidity returns whether applicable controls satisfy their constraints and can fire invalid events. ReportValidity also asks the browser to present native feedback. Validity exposes flags such as valueMissing, typeMismatch, rangeOverflow and stepMismatch.

SetCustomValidity supplies a custom error string. A non-empty message keeps the control invalid; clear it with an empty string when rechecking or after editing. Forgetting to clear it can leave a corrected field blocked.

The request lab trims a 2–60-character display name, uses native single-email type checking with a 100-character limit, accepts a known session and integer places from 1–4, and checks that the selected session has enough places. HTML has three available places and JavaScript has two. A checked confirmation is required.

placesInput.setCustomValidity("");
if (requested > available) {
  placesInput.setCustomValidity("Request no more than the available places.");
}
const valid = form.checkValidity();

The lab accepts decimal-digit place entries such as 2; fractional or exponential spellings are rejected. It checks native validity and displays inline messages rather than calling reportValidity for competing popup feedback. Email type checking is a syntax check, not proof of ownership or deliverability.

13

FormData — Inspect Successful Controls

New FormData(form) collects successful named controls according to the form rules. Disabled controls are omitted. An unchecked checkbox is omitted. A name is needed for an ordinary field to contribute an entry.

Text and numeric control values usually arrive as strings; a number input does not make FormData produce a Number. Repeated field names can have multiple entries, so getAll is useful when multiple values are intended.

A submit button’s name/value depends on how the submitter is included. This lab’s submit button has no name and constructs FormData from the form. It shows the raw entries alongside an explicitly normalized places Number.

const data = new FormData(form);
const entries = Array.from(data.entries());
const places = Number(data.get("places"));
console.log(entries, places);

The optional updates checkbox has value "yes" and appears only when checked. The required confirmation appears in accepted data. The preview never assumes an omitted checkbox entry is the string "false".

14

requestSubmit, submit and reset

RequestSubmit follows a submission workflow similar to activating a submit button: it participates in validation and dispatches submit when the workflow permits. Form.submit bypasses the submit event and constraint validation. They are not interchangeable helpers.

Avoid naming a form control submit when the code needs form.submit, because named controls can mask that method. Use descriptive field names and keep the submission API clear.

Form.reset restores controls to their default states rather than automatically making every field empty. It does not clear every custom error, application result or generated message; clear those parts deliberately.

form.requestSubmit(); // validation/submit workflow
// form.submit() has different behavior and bypasses that handler.

form.reset();
field.setCustomValidity("");
error.textContent = "";

The lab’s reset returns to a blank name/email/session, one requested place and unchecked checkboxes. It clears inline validity messages, preview data and the attempt count, then focuses the name field.

15

Errors, Focus and Honest Outcomes

Give each field error a nearby text message and connect it with aria-describedby. Set aria-invalid when the attempted entry is rejected. A concise status reports the attempt outcome while the detailed errors remain associated with their controls.

Focus the first invalid field after submission. Keep all entered values so the learner can correct them. On successful local preview, keep the form usable rather than replacing it with a success screen that hides the controls.

Client validation does not reserve a seat or prove that a server accepted a request. The lab reports a local accepted preview. A real network form would need loading, server validation, response handling and a deliberate policy for repeated attempts; those concerns follow in the asynchronous lesson.

A useful rejection
Field text

Describe the specific correction.

Focus

Move to the first invalid control.

Status

Report a concise overall result.

Retry

Keep values and validate the corrected attempt.

16

Premium Visualizer — Form Event Journey

Follow the fixed submission path through activation, cancellation, validation, collection and reporting. Use the familiar timeline and playback controls. The lab below exposes actual event listeners and a separate form workflow.

EVENTS AND FORM TRACE
Step 1 of 5
STEP 01

Activate the native submit control

The form workflow reaches its submit listener in the local novalidate demo.

form.addEventListener("submit", handler)

What is happening?

A native form workflow is broader than one button click. This lab deliberately uses inline validation.

17

Premium Interactive — Event Path and Form Lab

First choose a propagation mode and activate the nested link by clicking its text or using Enter. Inspect the observed target, currentTarget, phase and defaultPrevented values. The link points to a nearby marker in this lesson. Cancel navigation prevents that fragment action while propagation continues; stop propagation keeps the fragment action but stops the later ancestor listeners.

Then use fictional values in the local workshop-request form. The handler cancels default submission, combines native validity with the stated task rules and previews FormData locally. No personal details are sent or saved by this lab. Corrected fields are rechecked on the next attempt.

Event path playground

Outer region

Local navigation marker for the event experiment.

Activate the link to inspect its event path.

[]

Local workshop-request preview

Use fictional values. HTML has 3 places available; JavaScript has 2. Each request must contain 1–4 whole places and fit the selected availability.

The form becomes available when its local handler is ready.

Submission outcome

No accepted preview yet.
18

Debugging — Identify the Event and the Workflow

Handler

Check event type, function identity and duplicate setup.

Path

Inspect target, currentTarget, phase and stopping point.

Validity

Clear stale custom errors and inspect native flags.

Data

Check names, checkbox state, strings and omitted controls.

If preventDefault appears to do nothing, check cancelable and passive status. If an ancestor handler is absent, inspect whether propagation was stopped earlier. If Enter misses validation, inspect whether only a click listener exists. If a corrected field stays invalid, check its custom validity message.

If an optional checkbox is absent from FormData, inspect whether it is checked. If a numeric comparison treats a string unexpectedly, convert deliberately and validate the whole entry. If every click increments an attempt twice, look for two listeners processing the same submit.

Repeat a small workflow: blank attempt, fill valid fields, request too many places, correct places, preview once, edit one field and reset. Keep the event log and form outcome separate so a link click is not mistaken for a form submission.

19

Interview Questions — Flip to Explain

QUESTION

Why handle a form’s submit event rather than only its button click?

Click or press Enter to explain
ANSWER

Submit represents the form workflow, including supported implicit submission and requestSubmit. A click-only handler can miss other submission paths.

QUESTION

How do target and currentTarget differ?

Click or press Enter to explain
ANSWER

Target identifies the exposed event target; currentTarget identifies the object whose listener is currently running.

QUESTION

Does preventDefault stop bubbling?

Click or press Enter to explain
ANSWER

No. It cancels an applicable default action; propagation continues unless separately stopped.

QUESTION

Does stopPropagation cancel a link’s navigation?

Click or press Enter to explain
ANSWER

No. It stops further propagation, but default cancellation requires preventDefault when the event is cancelable.

QUESTION

What makes delegation useful for dynamic cards?

Click or press Enter to explain
ANSWER

A stable parent can observe a suitable bubbling event from descendants inserted later, while checking the intended target and scope.

QUESTION

Why clear setCustomValidity before rechecking?

Click or press Enter to explain
ANSWER

A non-empty custom message keeps a control invalid even after its visible value is corrected.

QUESTION

What does FormData do with an unchecked checkbox?

Click or press Enter to explain
ANSWER

It normally omits that control’s entry. The missing entry is not automatically the text false.

QUESTION

How do requestSubmit and submit differ?

Click or press Enter to explain
ANSWER

RequestSubmit follows the validation and submit-event workflow. The submit method bypasses constraint validation and the submit event.

20

MCQ Practice — Explain the Event and Form

PRACTICE

1. Which value should be passed to addEventListener as a callback?

PRACTICE

2. Which property identifies the object whose listener is running?

PRACTICE

3. Which observed listener runs first in the normal playground path?

PRACTICE

4. What does preventDefault do for this cancelable link click?

PRACTICE

5. What does stopPropagation do in the link listener?

PRACTICE

6. Which event should handle the request form’s workflow?

PRACTICE

7. What does novalidate change in this demo?

PRACTICE

8. Which value clears a custom validity error?

PRACTICE

9. How does FormData ordinarily represent a number input?

PRACTICE

10. What happens to the unchecked optional updates checkbox?

PRACTICE

11. Which method bypasses submit listeners and constraint validation?

PRACTICE

12. How many places can an accepted JavaScript request contain here?

21

Extra Practice — Test Specific Interactions

Normal path

Activate the nested link in normal mode. Expected: five observed listeners; target and listener IDs can differ.

Cancellation

Choose cancel navigation. Expected: five observed listeners and defaultPrevented becomes true at the link listener.

Stopping

Choose stop propagation. Expected: two capture entries plus the link entry; later inner/outer bubble entries are absent.

Blank attempt

Submit untouched fields. Expected: inline required errors and focus on the name field.

Accepted values

Use Demo Learner, learner@example.com, HTML, 3 places and confirmation. Expected: a local accepted preview with numeric places 3.

Capacity rule

Choose JavaScript and 3 places. Expected: places error because only two are available.

Optional entry

Preview with updates unchecked, then checked. Expected: updates omitted, then updates="yes".

Correction/reset

Correct an invalid place count and retry, then reset. Expected: stale error clears, one handling result per attempt and defaults restored.

22

Quick Revision

Listeners: Register callbacks without calling them immediately.
Targets: Separate target from current listener identity.
Path: Capture and bubble describe propagation order.
Cancel: Default action and propagation are separate decisions.
Delegation: Use a stable parent and checked descendant target.
Editing: Clear stale messages without claiming full validity.
Submit: Handle the form workflow once.
Validation: Combine native constraints and explicit task rules.
FormData: Understand strings and omitted controls.
Outcome: Preserve correction paths and report local scope honestly.
23

Glossary — Flip to Learn

TERM

Event

Click to see meaning
DEFINITION

Event

An object representing an occurrence dispatched through event targets.

TERM

Listener

Click to see meaning
DEFINITION

Listener

A callback registered to respond to an event type.

TERM

Target

Click to see meaning
DEFINITION

Target

The event target exposed to the current listener.

TERM

Current target

Click to see meaning
DEFINITION

Current target

The object whose event listener is currently running.

TERM

Capture

Click to see meaning
DEFINITION

Capture

Propagation toward the target through applicable ancestor listeners.

TERM

Bubbling

Click to see meaning
DEFINITION

Bubbling

Propagation outward through applicable ancestor listeners.

TERM

Default action

Click to see meaning
DEFINITION

Default action

A browser behavior associated with an event, such as navigation.

TERM

Delegation

Click to see meaning
DEFINITION

Delegation

Handling suitable descendant events through a parent listener.

TERM

Constraint validation

Click to see meaning
DEFINITION

Constraint validation

Checking controls against applicable native and custom validity rules.

TERM

Successful control

Click to see meaning
DEFINITION

Successful control

A form control that contributes data under the form-entry rules.

24

Final Challenge — A Clear Local Request Workflow

Build a labeled local workshop-request form with one submit handler. Keep native constraints in the HTML, explain any deliberate novalidate choice and enforce the selected session’s available places. Use nearby described errors, a concise status and a useful correction focus path.

Clear custom errors before the next check. Read FormData only for an accepted preview, show its raw strings and normalize the numeric places explicitly. Treat an unchecked optional checkbox as omitted. Preserve the form and user entries so a rejected request can be corrected.

Test blank values, malformed email, an unknown session, zero/fractional/too-many places, unchecked confirmation, accepted HTML 3, rejected JavaScript 3 and accepted JavaScript 2. Confirm one result per submit attempt and defaults after reset. Test native mouse and keyboard paths in a browser.

Success criterion: explain target/currentTarget, propagation versus cancellation, native versus custom checks and the scope of the local result. Level 18 will introduce asynchronous JavaScript and API requests.

25

Level 17 Complete?

Before marking complete, trace a nested event, cancel its default action deliberately, submit a form through its own listener and correct a field-specific error. Completion is a local study marker rather than an assessment score.