yewstack/yew · error
Event should have a target when dispatched
Error message
Event should have a target when dispatched
What it means
This panic comes from the `.expect()` on `Event::target()` in Yew 0.21's events guide (the `unchecked_into` recipe). `web_sys::Event::target()` returns `Option<EventTarget>` because the DOM permits events with no target: programmatically constructed events, events dispatched on `window`, or detached-target events. Yew passes the raw browser event through, so when the Option is None the expect panics and aborts the WASM app. For events fired by real user interaction on an `<input>` the target is effectively always present, so in practice this panic comes from tests or synthetic dispatch.
Source
Thrown at website/versioned_docs/version-0.21/concepts/html/events.mdx:155
Callback::from(move |e: Event| {
// When events are created the target is undefined, it's only
// when dispatched does the target get added.
let target: Option<EventTarget> = e.target();
// Events can bubble so this listener might catch events from child
// elements which are not of type HtmlInputElement
//highlight-next-line
let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());
if let Some(input) = input {
input_value_handle.set(input.value());
}
})
};
let on_dangerous_change = Callback::from(move |e: Event| {
let target: EventTarget = e
.target()
.expect("Event should have a target when dispatched");
// You must KNOW target is a HtmlInputElement, otherwise
// the call to value would be Undefined Behaviour (UB).
// Here we are sure that this is input element so we can convert it to the appropriate type without checking
//highlight-next-line
input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());
});
html! {
<>
<label for="cautious-input">
{ "My cautious input:" }
<input onchange={on_cautious_change}
id="cautious-input"
type="text"
value={input_value.clone()}
/>
</label>
<label for="dangerous-input">View on GitHub (pinned to 0e4a05472f)
Solutions
- Handle the Option instead of expecting: `let Some(target) = e.target() else { return; };`
- Replace the UB-prone `target.unchecked_into::<HtmlInputElement>()` with `e.target_dyn_into::<HtmlInputElement>()`, which checks presence and type in one call — the same pattern the events guide recommends in its safer section
- In tests, dispatch the change event from the actual input element (`input.dispatch_event(&event)`) so the target is populated
Example fix
// before
let target: EventTarget = e
.target()
.expect("Event should have a target when dispatched");
input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());
// after
if let Some(input) = e.target_dyn_into::<HtmlInputElement>() {
input_value_handle.set(input.value());
} Defensive patterns
Strategy: type-guard
Validate before calling
let on_dangerous_change = Callback::from(move |e: Event| {
let Some(target) = e.target() else {
gloo::console::warn("change event without target, ignoring");
return;
};
// only proceed with a present target
let _ = target;
}); Type guard
use wasm_bindgen::JsCast;
use web_sys::{Event, HtmlInputElement};
fn input_target(e: &Event) -> Option<HtmlInputElement> {
// presence check + instanceof HtmlInputElement in one call
e.target_dyn_into::<HtmlInputElement>()
} Prevention
- Never combine target().expect() with unchecked_into on event targets — use TargetCast::target_dyn_into, which returns Option
- Treat every web_sys Option-returning getter as fallible in test code
- Dispatch synthetic events from a real element in wasm-bindgen-test instead of constructing bare Events
- Keep shared event-destructuring helpers in one module so no handler repeats the expect pattern
When it happens
Trigger: Registering the guide's `on_dangerous_change` callback and delivering an event without a target: calling the callback from a `wasm-bindgen-test` with `Event::new(...).unwrap()` (never dispatched, so target is None), `window.dispatchEvent(...)`, or shadow-DOM retargeted synthetic events.
Common situations: Copy-pasting the Yew 0.21 events.mdx snippet (~line 155) into an app or test suite; migrating handlers so they now receive the generic `Event` type; headless component tests that synthesize `change` events instead of dispatching them from a real input element.
Related errors
- Event should have a target when dispatched
- Event should have a target when dispatched
- I'm sure this event has a target!
- mouse event doesn't have a target
- I'm sure this event has a target!
AI-assisted analysis of yewstack/yew@0e4a05472f (2026-08-22).
Data as JSON: /api/errors/0b06dcc974a14f67.
Report an issue: GitHub.