---
title: 'Default Behavior and Cancellation'
source: 'https://academia.sh/en/courses/browser-platform/default-behavior-and-cancellation'
course: 'The Browser and the Web Platform'
language: en
updated: '2026-08-17T18:09:11+00:00'
license: 'CC BY-SA 4.0'
---

# Default Behavior and Cancellation

The browser's built-in response to events and the request to cancel it; the cancelability condition, why cancellation is not the same as stopping propagation, the passive listener's constraint, and when cancellation is legitimate.

In previous lessons, listeners only added: an event arrived, code ran, a behavior was
attached to the page. But the browser has its own behaviors too, and they work with no
listener at all. Clicking a link starts navigation, a submit button submits the form, a
checkbox toggles its checked state, the space bar scrolls the page.

When a listener wants to put its own behavior in place of these, it has to cancel the
work the browser was going to do. This lesson establishes how cancellation is requested,
under what conditions it is accepted, and why it is not the same thing as stopping
propagation.

## The Default Action

An event's **default action** is the browser's built-in response to that event. It is
written neither in the document nor in the style; it comes from the meaning of the
markup. Because a link element means "leads to another resource," navigation starts when
it is clicked. Because a submit button means "submits the form," the entry list is
prepared when it is clicked.

Two properties of the default action are critical.

The first is its **order**. The default action runs after the event's propagation
finishes. Any listener along the propagation path — as much the target's as the
ancestors' — can cancel the action. An ancestor node's listener in the bubble phase can
stop a navigation that started at the target.

The second is **chainability**. Some default actions produce a new event. Clicking a
label produces a click event on the form field it is bound to; that click has its own
default action too. A single user gesture can therefore produce more than one event and
more than one default action; which link of the chain the cancellation happens at
determines the result.

## The Cancellation Request

A listener requests cancellation through the event object. The request is not always
accepted: the event has to be **cancelable**. Some events, like a scroll notification, are
produced after the browser has already done the work, and cannot be cancelled; the
request is silently ignored.

```js
// default.mjs — propagation, cancellation, and the order of the default action
const element = (name, ...children) => {
  const d = { name, children, parent: null, listeners: [] };
  for (const c of children) c.parent = d;
  return d;
};
const listen = (node, label, action, passive = false) =>
  node.listeners.push({ label, action, passive });

function dispatch(target, { type, cancelable, defaultAction }) {
  const chain = [];
  for (let d = target; d; d = d.parent) chain.push(d);

  const event = { type, cancelable, defaultPrevented: false, stopped: false };
  const log = [];
  event.preventDefault = function () {
    if (this.inPassiveListener) return log.push("  [ignored] passive listener");
    if (event.cancelable === false) return log.push("  [ignored] non-cancelable event");
    event.defaultPrevented = true;
  };

  for (const node of chain) {          // bubble phase: target to root
    if (event.stopped) break;
    for (const d of node.listeners) {
      event.inPassiveListener = d.passive;
      log.push(`  ${node.name}/${d.label} (prevented=${event.defaultPrevented})`);
      d.action?.(event);
    }
  }
  log.push(event.defaultPrevented ? `  default action: cancelled` : `  default action: ${defaultAction}`);
  return log;
}

function tree(setUpListeners) {
  const link = element("a");
  const nav = element("nav", link);
  element("main", nav);
  setUpListeners(link, nav);
  return link;
}
const CLICK = { type: "click", cancelable: true, defaultAction: "navigation" };

const scenarios = [
  ["unimpeded", CLICK, (link, nav) => { listen(link, "link"); listen(nav, "nav"); }],
  ["preventDefault", CLICK, (link, nav) => {
    listen(link, "link", (o) => o.preventDefault()); listen(nav, "nav");
  }],
  ["stopPropagation", CLICK, (link, nav) => {
    listen(link, "link", (o) => { o.stopped = true; }); listen(nav, "nav");
  }],
  ["non-cancelable event", { type: "scroll", cancelable: false, defaultAction: "scrolling" },
    (link) => { listen(link, "link", (o) => o.preventDefault()); }],
  ["passive listener", { type: "wheel", cancelable: true, defaultAction: "scrolling" },
    (link) => { listen(link, "link", (o) => o.preventDefault(), true); }],
];

for (const [name, eventDef, setUp] of scenarios) {
  console.log(name);
  for (const line of dispatch(tree(setUp), eventDef)) console.log(line);
}
```

```
unimpeded
  a/link (prevented=false)
  nav/nav (prevented=false)
  default action: navigation
preventDefault
  a/link (prevented=false)
  nav/nav (prevented=true)
  default action: cancelled
stopPropagation
  a/link (prevented=false)
  default action: navigation
non-cancelable event
  a/link (prevented=false)
  [ignored] non-cancelable event
  default action: scrolling
passive listener
  a/link (prevented=false)
  [ignored] passive listener
  default action: scrolling
```

In the second scenario, the listener at the target requests cancellation; the event
continues on its path, and the listener at the ancestor node reads `prevented=true`. In
the browser API, this flag's name is `defaultPrevented`. Propagation continuing is not a
defect, it is the design itself: later listeners on the path can see the decision and
adjust their own behavior to it.

## Separating Cancellation from Stopping

The third scenario shows this lesson's most commonly confused point. Propagation was
stopped — the ancestor listener was never called — but navigation still happened.

The two operations are **independent of each other**:

- Stopping propagation prevents the event from reaching **other listeners**. It does not
  touch the browser's own behavior.
- Requesting cancellation prevents **the browser's behavior**. It does not prevent the
  event from continuing on its path.

Two mistakes follow from this. First, code that wants to stop navigation but stops
propagation instead does not stop the navigation. Second, code that only wants to do its
own work but stops propagation along with cancellation silently disables delegated
listeners elsewhere on the page. The two operations should be requested separately, and
in most cases only one of them is needed.

## The Passive Listener

The last scenario shows a different constraint. In scroll-related events, the browser
faces a dilemma: it cannot start scrolling without knowing whether the listener will
cancel it or not. For this reason, it waits for the listener to finish; a long-running
listener holds up the page under the user's finger.

A **passive listener** removes this uncertainty. With an option given at registration
time, the listener announces "I will not request cancellation"; the browser starts
scrolling without waiting for the listener. If cancellation is requested contrary to the
announcement, the request is ignored.

A practical rule follows from this: listeners that observe scrolling but do not change it
are registered as passive. A listener that puts its own behavior in place of scrolling
cannot be passive and accepts the cost of being waited for.

## The Fine Points of Cancellation

**In some events, cancellation means permission.** In a drag-and-drop operation, the
default action of the event produced while passing over an element is "refuse the drop";
the drop does not happen unless it is cancelled. Here, requesting cancellation does not
block the behavior, it opens it instead. This is why the assumption "cancellation always
blocks" is wrong; what an event's default action is needs to be known separately for each
one.

**Cancellation may not undo state.** When a checkbox is clicked, the checked-state change
happens before the event propagates; cancellation reverts the change. The current value
read inside the listener may therefore no longer be valid after cancellation.

**Something needs to be put in place of a cancelled action.** A page that cancels a
form's submission and sends the data itself in its own code behaves correctly. A page
that cancels submission and puts nothing in its place ends the user's task with no
visible reason. The same principle applies to links: code that cancels navigation also
takes away the user's ability to open it in a new tab with the middle button, copy the
address, or see where the link goes.

**Keyboard and accessibility behaviors are not cancelled.** A page that cancels the tab
key's focus-moving behavior becomes unusable by keyboard. Likewise, cancelling text
selection, the right-click menu, and zooming takes away the user's control. These
behaviors are cancelled only when an equivalent path is put in their place; the limits of
this are set in the Focus and Keyboard Interaction lesson.

## Cancellation's Irreversibility

A flag being readable does not mean it is changeable. There is no operation that undoes a
cancellation. The first cancellation request on the path settles the decision; later
listeners only see it.

The design consequence of this is: the decision to cancel should be made by the listener
that **owns** the behavior. Code that will cancel the measurement form's submission is the
form's own listener; a general listener looking at the form from the outside makes the
decision without seeing the form's own logic.

The same certainty holds in the reverse direction too. If a listener requests
unconditional cancellation at an early point in propagation, it is not possible for later
listeners to bring the behavior back; the only remedy is moving the condition inside that
listener. As long as the condition stays outside, cancellation turns into a switch that
silently and permanently shuts the behavior off.

Leaving the page is the most visible example of this rule. A page with unsaved changes
can cancel the event produced before leaving and have the browser ask for confirmation.
The page does not determine the confirmation's text or form; the browser does, and it
usually requires the user to have interacted with the page beforehand. The rule is the
same: a cancellation request is a suggestion, and it finds a response only within the
browser's acceptance conditions.

## Summary

- The default action is the browser's built-in response to an event, coming from the
  meaning of the markup; it runs after propagation finishes.
- Every listener on the propagation path can request cancellation; the request is
  accepted only when the event is cancelable, otherwise it is silently ignored.
- Cancellation and stopping propagation are independent operations: one blocks the
  browser's behavior, the other blocks the event from reaching other listeners.
- The event continues on its path even after being cancelled; later listeners can read
  the decision through a flag but cannot undo it.
- A passive listener announces ahead of time that it will not request cancellation; the
  browser starts scrolling without waiting, and a contrary request is ignored.
- In some events, cancellation means permission, not blocking; every cancelled behavior
  needs an equivalent path put in its place.

## Next Step

This lesson set the keyboard apart among behaviors that should not be cancelled and left
the reason for later. The reason is this: not all interaction with the page is built with
a pointing device. The user moves between elements with the tab key, presses a button with
space, moves between options with the arrow keys; a screen reader follows the same path.
At the center of this movement is a single concept: at any moment, at most one element in
the document receives input. The next lesson covers how this element is determined, what
the order is built from, and what information keyboard events carry.
