{"record":{"id":"dde4de69a9f7910c","repo":"yewstack/yew","slug":"mouse-event-doesn-t-have-a-target","errorCode":null,"errorMessage":"mouse event doesn't have a target","messagePattern":"mouse event doesn't have a target","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"website/versioned_docs/version-0.21/concepts/basic-web-technologies/web-sys.mdx","lineNumber":173,"sourceCode":"version = \"0.3\"\n# We need to enable all the web-sys features we want to use!\nfeatures = [\n    \"console\",\n    \"Document\",\n    \"HtmlElement\",\n    \"MouseEvent\",\n    \"DomRect\",\n]\n```\n\n```rust ,no_run\nuse wasm_bindgen::{prelude::Closure, JsCast};\nuse web_sys::{console, Document, HtmlElement, MouseEvent};\n\nlet mousemove = Closure::<dyn Fn(MouseEvent)>::wrap(Box::new(|e| {\n    let rect = e\n        .target()\n        .expect(\"mouse event doesn't have a target\")\n        .dyn_into::<HtmlElement>()\n        .expect(\"event target should be of type HtmlElement\")\n        .get_bounding_client_rect();\n    let x = (e.client_x() as f64) - rect.left();\n    let y = (e.client_y() as f64) - rect.top();\n    console::log_1(&format!(\"Left? : {} ; Top? : {}\", x, y).into());\n}));\n\nDocument::new()\n    .expect(\"global document not set\")\n    .get_element_by_id(\"mousemoveme\")\n    .expect(\"element with id `mousemoveme` not present\")\n    .unchecked_into::<HtmlElement>()\n    .set_onmousemove(mousemove.as_ref().dyn_ref());\n\n// we now need to save the `mousemove` Closure so that when\n// this event fires the closure is still in memory.\n```","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/yewstack/yew/blob/0e4a05472fac4e5fce1befe60fa4a1e43a36b6a3/website/versioned_docs/version-0.21/concepts/basic-web-technologies/web-sys.mdx#L155-L191","documentation":"The web-sys tutorial expects e.target() inside a mousemove handler attached with set_onmousemove. Real browser mousemove events always carry a target, so in production this expect can only fire for MouseEvent objects synthesized by application code or tests without a target. The snippet is illustrative; shipping code should not assume target presence.","triggerScenarios":"Manually constructed/dispatched MouseEvents reaching this handler (tests, automation or replay tooling calling dispatchEvent on bare events); reusing the tutorial listener for other event types whose target can be null.","commonSituations":"Simulating pointer movement in tests; automation scripts synthesizing events; copy-pasted tutorial code later pointed at different event sources.","solutions":["Use e.current_target() - the element the listener is bound to - which is always present during dispatch","Guard with if let Some(target) = e.target()","When synthesizing events in tests, dispatch them from a real element so target is set","Treat the snippet as a starting point and add Option handling before shipping"],"exampleFix":"// before\nlet rect = e.target()\n    .expect(\"mouse event doesn't have a target\")\n    .dyn_into::<HtmlElement>().unwrap()\n    .get_bounding_client_rect();\n\n// after: the element the listener is attached to - no Option panic\nlet rect = e.current_target()\n    .dyn_into::<HtmlElement>()\n    .expect(\"listener is bound to an HtmlElement\")\n    .get_bounding_client_rect();","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"fn mousemove_element(e: &web_sys::MouseEvent) -> Option<web_sys::Element> {\n    e.current_target().and_then(|t| t.dyn_into::<web_sys::Element>().ok())\n}","tryCatchPattern":null,"preventionTips":["Bind geometry math to current_target() (the element you attached the listener to), not target()","Handle the Option from target() instead of expecting it","Dispatch synthetic MouseEvents from real elements in tests"],"tags":["events","docs","web-sys","mouse-event"],"backgroundTag":"event-target-missing","analyzedSha":"0e4a05472fac4e5fce1befe60fa4a1e43a36b6a3","analyzedAt":"2026-08-22T21:16:31.212Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}