Input layers
Input events are not broadcast to every component; they are dispatched by the central InputRuntime. During each frame’s update phase, components register input layers and handlers again. When a terminal event arrives, the runtime sends it only to currently active layers.
To see a complete running example first, start with Input isolation.
Dispatch order
Section titled “Dispatch order”Dispatch has two phases:
| Phase | Candidate handlers | Ordering |
|---|---|---|
| Global | EventScope::Global | priority desc, order asc |
| Layer | Handlers in active input layers | z-order desc, priority desc, order asc |
z-order beats priority. A Normal handler in an upper layer runs before a High handler in a lower layer; otherwise a component behind a modal could still steal the event.
Three core types
Section titled “Three core types”InputLayer is the handle for the current frame’s layer:
When open=false, a handle is returned but the layer is not pushed, and handlers bound to it are silently skipped. When blocks_lower=true, this layer cuts off lower layers.
EventScope decides which layer a handler belongs to:
Current resolves to the nearest current layer in context. Components inside a Modal subtree usually only need Current; parent components that want to control modal keys should bind explicitly with Layer(layer).
EventResult decides whether the event continues propagating:
Return Consumed after handling an event. Return Ignored when this handler did not handle it, so later same-layer handlers or lower layers can try.
Hit testing
Section titled “Hit testing”By default, a handler receives all keyboard and mouse events in its layer. For cases where mouse input should be handled only inside a component’s area, use use_event_handler_with_options:
hit_test affects only mouse events. Keyboard events have no coordinates and are still delivered by layer, priority, and registration order. The hit area comes from the owning component’s previous-frame drawn Rect, so it is appropriate for local mouse wheel, click, and drag interactions. Do not use it to express modal isolation; modal isolation should still use InputLayer.
Modal pairing
Section titled “Modal pairing”The standard modal isolation pattern:
Modal(layer: Some(layer)) must receive the same layer used by the handler. If you omit it, Modal opens a new layer and cuts off the parent’s layer, so the parent handler no longer receives events.
Lifecycle
Section titled “Lifecycle”InputLayer handles are rebuilt every frame and should only be passed to handlers or child components in that same frame. Do not store one in State; on the next frame, that ID is no longer in the active layer stack.
This is also why the input system does not leak: after a modal closes, the next frame no longer registers its layer or handlers, so dispatch naturally cannot find them.
Built-in components
Section titled “Built-in components”Prefer built-in components for ordinary interactions:
| Need | Component |
|---|---|
| Search input | SearchInput |
| Confirmation dialog | ConfirmModal |
| Alert dialog | AlertModal |
| Shortcut help | ShortcutInfoModal |
These components already wire their input layers internally. Application code only handles open, callbacks, and displayed content. Write use_input_layer, use_event_handler(EventScope::Layer(...)), and Modal(layer: Some(...)) by hand only for specialized modal interactions.