RFC: Internal Event Propagation #256
tzdesign
started this conversation in
Proposals For Qwik
Replies: 1 comment 1 reply
-
@tzdesign thanks! this sounds like a bug in the original implementation no? |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
What is it about?
stopPropagation should work in qwik as it does native in javascript
What's the motivation for this proposal?
Summary
Provide full, predictable control over DOM event propagation in Qwik so that
event.stopPropagation()
andevent.stopImmediatePropagation()
behave like native browser JavaScript across both user-defined and Qwik internal/system handlers (e.g. action submission, router SPA resets, form enhancement logic). Today, internal dispatch continues executing subsequent handlers even if a previous handler signaled propagation stop, leading to surprising side effects.Motivation
Developers expect browser event semantics. In current Qwik versions:
on<Event>$
handlers can callevent.stopPropagation()
orevent.preventDefault()
.<form>
) with internal system handlers (actions, SPA navigation, form serialization, optimistic UI, etc.).This causes:
action.submit
) still fire even when a first-step handler attempts to gate or defer execution viastopPropagation()
.Current form flow:
If
onSubmit$
callsevent.stopPropagation()
(or evenevent.preventDefault()
),action.submit
still runs.Goals
stopPropagation()
andstopImmediatePropagation()
across any chained Qwik handler list.Current Behavior Details
Qwik normalizes multi-handlers (
onClick$: [a, b, c]
). Internally it iterates and invokes each registered QRL. The iteration does not check flags set by previous handlers (defaultPrevented
, custom markers, etc.). System handlers are appended into these arrays or registered separately, bypassing native bubbling semantics because execution is flattened.Proposed Solution / Feature
Proposed Design
Leverage the fact that Qwik already passes the native browser
Event
object through all handlers. Instead of creating a shadow/augmented event, simply observe native flags after each handler invocation.Key idea: After each handler in a multi-handler list executes, check:
event.cancelBubble
(set bystopPropagation()
and also bystopImmediatePropagation()
). If true, stop invoking remaining handlers in the list for the current target.stopImmediatePropagation()
(optional). If differentiation isn't required, treating both the same is sufficient for the Qwik internal chaining use case.event.defaultPrevented
for specific internal handlers (e.g. form auto-submit) that should respect a prevented default.This keeps implementation minimal, avoids monkey-patching, and fully reuses native semantics already implemented and optimized by browsers.
Internal Implementation Sketch
stopPropagation()
, they are skipped.preventDefault()
, wrap their execution:Rationale For Using
cancelBubble
event.cancelBubble
is a long-standing, standardized boolean alias internally flipped by bothstopPropagation()
andstopImmediatePropagation()
. Reading it avoids patching and symbol bookkeeping. The inability to distinguish the two calls is acceptable because Qwik's current issue is continuation after ANY propagation stop request. If finer granularity is ever required, a minimal patch ONLY forstopImmediatePropagation
can be added in strict mode.Performance Considerations
ev.cancelBubble
) after each handler (ultra-cheap, no augmentation cost).defaultPrevented
when relevant.Expected overhead: negligible compared to handler invocation itself.
Edge Cases
await
returns.Alternatives Considered
Shadow / augmented event with symbol flags – more code & minor overhead; no longer necessary.
Testing Strategy
Documentation Updates
Add section "Event Propagation Control" to Qwik docs:
cancelBubble
Open Questions
preventDefault()
ALSO skip internal submissions by default? (Likely yes for forms.)Drawbacks
Conclusion
Aligning Qwik's internal event handling with the native DOM propagation contract reduces surprise, improves composability, and simplifies app logic.
Links / References
No response
Beta Was this translation helpful? Give feedback.
All reactions