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

  1. Handle the Option instead of expecting: `let Some(target) = e.target() else { return; };`
  2. 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
  3. 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

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


AI-assisted analysis of yewstack/yew@0e4a05472f (2026-08-22). Data as JSON: /api/errors/0b06dcc974a14f67. Report an issue: GitHub.