prevent() and stop()
actionsince 0.7.0experimentalrequires runtimeEvent modifiers for :on(): prevent() cancels the browser's default for the event, stop() ends the event at the element so ancestors do not see it.
On this page · 10 sections+−
Syntax
:on(<event>, prevent());:on(<event>, stop());:on(<event>, prevent(), stop());registry syntax: prevent()
Parameters
None.
Effect
No value. prevent() calls event.preventDefault() synchronously while the event is dispatched. stop() calls event.stopPropagation() when the event reaches the element.
Example
.tabs { --active: state(1);}.tabs [role=tablist]:on(keydown(ArrowRight), prevent()) { --active: cycle(1, 2, 3);}Correct and incorrect usage
correctHandle the arrow keys of a tab list, leave every other key alone
.tabs { --active: state(1); }.tabs [role=tablist]:on(keydown(ArrowRight), prevent()) { --active: cycle(1, 2, 3);}.tabs [role=tablist]:on(keydown(ArrowLeft), prevent()) { --active: cycle(3, 2, 1);}Only ArrowRight and ArrowLeft are cancelled, so the page does not scroll while they move the selection. Tab, Space and PageDown keep their native behavior.
correctAsk before a link navigates
.delete { --asking: state(false); }.delete a:on(click, prevent()) { --asking: set(true);}The link does not navigate; the state can show a confirmation. Without the script, the link works as a normal link.
correctKeep a click inside a card
.list { --selected: state(0); }.card { --open: state(false); }.list .card:on(click) { --selected: set(sibling-index()); }.card .more:on(click, stop()) { --open: toggle(); }A click on .more opens the card without selecting it: stop() keeps the event from the ancestor's rule.
correctCancel only while a condition holds
.reader { --locked: state(false); }.reader .page:on(keydown(PageDown)) { --locked: toggle();}.reader:when(--locked) .page:on(keydown(PageDown), prevent()) {}An element gets prevent() when any rule that applies to it for that event has it, and :when() is current for every event. PageDown scrolls while --locked is false and is cancelled while it is true. The rule with only a modifier is empty on purpose: keep it through minification.
incorrectA click rule on a container
.card { --open: state(false); }.card:on(click, prevent()) { --open: toggle();}This compiles, but it cancels the default of every click inside .card: links stop navigating, submit buttons stop submitting, checkboxes stop toggling and <summary> stops opening. Put the rule on the element whose default you mean to cancel.
incorrectprevent() on an event that cannot be cancelled
.search { --typing: state(false); }.search input:on(input, prevent()) { --typing: set(true);}A compile error: input events are not cancelable, so the rule is ignored.
incorrectA bare modifier
a.confirm:on(click, prevent) { --asking: set(true);}A compile error that asks for the function form, prevent().
Behavior
- Modifiers, not actions. They follow the event in the selector, as functions:
:on(click, prevent()),:on(keydown(Escape), prevent(), stop()). A barepreventorstopis a compile error that asks for the function form. The rule's declarations hold only state mutations; a modifier-only rule such asa.confirm:on(click, prevent()) {}is allowed. - Why `prevent()` exists. A handled key, such as an arrow key in a tab list, would also scroll the page, and a click on a link would also navigate.
prevent()cancels that native default for the event the rule handles, and only that one. - Synchronous. The browser decides the default while the event is dispatched, so a cancellation in the next frame would be too late.
prevent()runs inside the library's delegated listener, during dispatch. That listener is non-passive only for event types that a live rule cancels; pages withoutprevent()keep passive listeners. - Any rule wins. The element gets
prevent()if any rule that applies to it for that trigger has it, with conditions that are current for every event. - `stop()`.
:on()rules on the element's ancestors do not run for this event; the element's own rules still run. The native propagation stops at the element too, withstopPropagation()(neverstopImmediatePropagation()), so ancestors' listeners do not see the event. Listeners on the element and its descendants still receive it, and the capture phase is never stopped.outside()rules elsewhere are not affected. - Form controls keep their keys. A key pressed in an
input,textarea,selector editable element is not cancelled by a rule on an ancestor. A rule on the control itself can cancel it. - Non-cancelable events. If
event.cancelableis false (for example a script-created event withoutcancelable: true), nothing is cancelled and a warning is logged.
Supported contexts
prevent():click,dblclick,contextmenu,mousedown,pointerdown,keydown,keyup,submitanddrag(where it cancels thepointerdown). Anywhere else it is a compile error, andoutside()never accepts it.stop(): every:on()event exceptoutside()and drag, where it is a compile error.- Trusted stylesheets only, like every
:on()rule.
Limitations
- Each modifier appears at most once, in either order, and takes no arguments:
prevent(1)and a repeatedstop()are compile errors. - There is no
oncemodifier: guard the rule with a state,.b:when(not --done):on(click) { --done: set(true); }. - A
clickrule withprevent()on a container also cancels clicks on links, buttons and form controls inside it (see the incorrect example above). - Minifiers that remove empty rules (esbuild
minifyorminifySyntax, csso, Lightning CSS) delete modifier-only rules such asa:on(click, prevent()) {}. Use whitespace-only minification. - Firefox has no automated test run; see Browser compatibility for the manual, user-reported pass.
Examples
- Accessible tabs · Test lab, runs the real runtime
- Keyboard navigation · Test lab, runs the real runtime
- Keyboard playground · Test lab, runs the real runtime
- Context menu · API examples, runs the real runtime