Events
wybthon.events¶
events
¶
Event delegation utilities for VDOM event handling in the browser.
Wybthon installs one root listener per event type on document
and dispatches to per-node handlers using a stable data-wybid
attribute. This keeps the number of native listeners small even for
large trees and lets the renderer add or remove handlers cheaply
during reconciliation.
Public surface:
DomEvent: a thin wrapper passed to handlers exposingtype,target,current_target, and helpers likeprevent_defaultandstop_propagation.
The remaining helpers are internal: set_handler,
remove_all_for, and the listener
ref-counting utilities are exercised by the renderer.
See Also
Classes:
| Name | Description |
|---|---|
DomEvent |
Thin wrapper around a JS event with convenience helpers. |
DomEvent
¶
DomEvent(js_event: Any)
Thin wrapper around a JS event with convenience helpers.
Attributes:
| Name | Type | Description |
|---|---|---|
type |
Event type string (e.g. |
|
target |
The original event target as an
|
|
current_target |
Optional[Element]
|
The currently-dispatched element while bubbling through delegated handlers; updated by the dispatcher. |
Wrap a raw JS event object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
js_event
|
Any
|
The native browser event object. |
required |
Methods:
| Name | Description |
|---|---|
prevent_default |
Prevent the default browser action for this event, if possible. |
stop_propagation |
Stop propagation through both the JS and the delegated chains. |
prevent_default
¶
Prevent the default browser action for this event, if possible.
stop_propagation
¶
Stop propagation through both the JS and the delegated chains.
Sets an internal flag that causes Wybthon's dispatcher to stop
walking the DOM ancestors, and also calls the native
stopPropagation so other JS listeners do not fire.
set_handler
¶
Attach, update, or remove a handler for an event property on an element.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
el
|
Element
|
Wrapped element to attach to. |
required |
event_prop_name
|
str
|
Prop name as seen on the |
required |
handler
|
Optional[Callable]
|
Callback to invoke. Pass |
required |
remove_all_for
¶
Remove every delegated handler registered for el.
Called by the renderer during unmount to drop the handler table and decrement the active-listener counters so unused root listeners are released.
Wybthon's event system provides delegated event handling and a thin DomEvent wrapper.
DomEvent: wrapper withtype,target(Element|None),current_target(Element|None),prevent_default(),stop_propagation().- Handlers can be attached via props like
on_click,on_input, oronChange. Names are normalized to DOM event types. - Delegation is automatic and handlers are cleaned up on unmount. Document-level delegated listeners are installed on first use per event type and are automatically removed when no handlers remain for that type (e.g., after unmount/diff removes all handlers).
Naming and normalization¶
- Any prop starting with
on_oronis treated as an event handler and normalized to a DOM event type. - Normalization rules:
on_clickbecomes "click"onInput/on_inputbecomes "input"onClick/onclickbecomes "click"- In general: remove the
on/on_prefix and lowercase the remainder.
Handler signature:
- All handlers receive a
DomEventobject. Useevt.prevent_default()andevt.stop_propagation()as needed. Access the original JS event viaevt._js_eventonly if absolutely necessary.
Delegation and bubbling¶
Wybthon installs one document-level listener per event type on first use and walks up from the original target to parent nodes, invoking any handlers registered for that event_type. stop_propagation() prevents further bubbling within Wybthon's dispatcher.
Cleanup guarantees:
- When a node is unmounted, all of its event handlers are removed from the delegation map.
- When the last handler for an event type is removed across the entire document (e.g., via unmount or by diffing a handler to
None), the document-level listener for that event type is automatically removed.
Common event types¶
You can attach handlers for any standard DOM event that bubbles. Commonly used types include:
- Mouse:
click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,contextmenu,wheel - Keyboard:
keydown,keyup(avoid deprecatedkeypress) - Input and form:
input,change,submit,reset - Focus: use
focusinandfocusout(see non-bubbling notes below) - Pointer:
pointerdown,pointerup,pointermove,pointerover,pointerout,pointercancel - Touch:
touchstart,touchmove,touchend,touchcancel - Composition/IME:
compositionstart,compositionupdate,compositionend - Drag and drop:
dragstart,dragend,dragenter,dragleave,dragover,drop
Wybthon does not restrict event type names; if the browser fires it and it bubbles, the delegated listener will see it.
Non-bubbling and special-case events¶
Because Wybthon uses document-level delegation, event types that do not bubble will not trigger handlers when attached via props. Use the suggested alternatives or attach a direct listener via wybthon.dom.Element.on using a Ref.
- Use
focusin/focusoutinstead offocus/blur(which do not bubble). - Use
mouseover/mouseoutinstead ofmouseenter/mouseleave(which do not bubble). - Many media events (e.g.,
play,pause) andscrolldo not bubble; attach direct listeners to the element or usewindow/documentas appropriate.
Direct listeners example (when you need non-bubbling events or options like passive: False):
from wybthon import component, h, on_mount, Ref
@component
def Video():
ref = Ref()
def setup():
if ref.current is not None:
ref.current.on("play", lambda e: print("playing"))
on_mount(setup)
return h("video", {"ref": ref})
Pyodide and cross-browser notes¶
- Event delegation relies on bubbling to
document. For non-bubbling types, prefer the alternatives above or attach direct listeners viaElement.on. - Chrome/Edge may treat
touchstart/touchmovelisteners ondocumentas passive by default, makingpreventDefault()a no-op. If you need to prevent scrolling, attach a direct listener withoptions={"passive": False}usingElement.onand aRef. keypressis deprecated and may behave inconsistently across browsers; preferkeydown/keyup.- The
DomEventwrapper exposes a stable, Python-friendly surface. Accessingevt._js_eventis possible but not recommended for portability across Pyodide and non-browser tests.