{"record":{"id":"0b06dcc974a14f67","repo":"yewstack/yew","slug":"event-should-have-a-target-when-dispatched","errorCode":null,"errorMessage":"Event should have a target when dispatched","messagePattern":"Event should have a target when dispatched","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"website/versioned_docs/version-0.21/concepts/html/events.mdx","lineNumber":155,"sourceCode":"        Callback::from(move |e: Event| {\n            // When events are created the target is undefined, it's only\n            // when dispatched does the target get added.\n            let target: Option<EventTarget> = e.target();\n            // Events can bubble so this listener might catch events from child\n            // elements which are not of type HtmlInputElement\n            //highlight-next-line\n            let input = target.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());\n\n            if let Some(input) = input {\n                input_value_handle.set(input.value());\n            }\n        })\n    };\n\n    let on_dangerous_change = Callback::from(move |e: Event| {\n        let target: EventTarget = e\n            .target()\n            .expect(\"Event should have a target when dispatched\");\n        // You must KNOW target is a HtmlInputElement, otherwise\n        // the call to value would be Undefined Behaviour (UB).\n        // Here we are sure that this is input element so we can convert it to the appropriate type without checking\n        //highlight-next-line\n        input_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());\n    });\n\n    html! {\n        <>\n            <label for=\"cautious-input\">\n                { \"My cautious input:\" }\n                <input onchange={on_cautious_change}\n                    id=\"cautious-input\"\n                    type=\"text\"\n                    value={input_value.clone()}\n                />\n            </label>\n            <label for=\"dangerous-input\">","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/yewstack/yew/blob/0e4a05472fac4e5fce1befe60fa4a1e43a36b6a3/website/versioned_docs/version-0.21/concepts/html/events.mdx#L137-L173","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet target: EventTarget = e\n    .target()\n    .expect(\"Event should have a target when dispatched\");\ninput_value_handle.set(target.unchecked_into::<HtmlInputElement>().value());\n\n// after\nif let Some(input) = e.target_dyn_into::<HtmlInputElement>() {\n    input_value_handle.set(input.value());\n}","handlingStrategy":"type-guard","validationCode":"let on_dangerous_change = Callback::from(move |e: Event| {\n    let Some(target) = e.target() else {\n        gloo::console::warn(\"change event without target, ignoring\");\n        return;\n    };\n    // only proceed with a present target\n    let _ = target;\n});","typeGuard":"use wasm_bindgen::JsCast;\nuse web_sys::{Event, HtmlInputElement};\n\nfn input_target(e: &Event) -> Option<HtmlInputElement> {\n    // presence check + instanceof HtmlInputElement in one call\n    e.target_dyn_into::<HtmlInputElement>()\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["yew","events","option-expect","wasm","panic"],"backgroundTag":"event-target-missing","analyzedSha":"0e4a05472fac4e5fce1befe60fa4a1e43a36b6a3","analyzedAt":"2026-08-22T21:16:31.212Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}