yewstack/yew · warning

mouse event doesn't have a target

Error message

mouse event doesn't have a target

What it means

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.

Source

Thrown at website/versioned_docs/version-0.21/concepts/basic-web-technologies/web-sys.mdx:173

version = "0.3"
# We need to enable all the web-sys features we want to use!
features = [
    "console",
    "Document",
    "HtmlElement",
    "MouseEvent",
    "DomRect",
]
```

```rust ,no_run
use wasm_bindgen::{prelude::Closure, JsCast};
use web_sys::{console, Document, HtmlElement, MouseEvent};

let mousemove = Closure::<dyn Fn(MouseEvent)>::wrap(Box::new(|e| {
    let rect = e
        .target()
        .expect("mouse event doesn't have a target")
        .dyn_into::<HtmlElement>()
        .expect("event target should be of type HtmlElement")
        .get_bounding_client_rect();
    let x = (e.client_x() as f64) - rect.left();
    let y = (e.client_y() as f64) - rect.top();
    console::log_1(&format!("Left? : {} ; Top? : {}", x, y).into());
}));

Document::new()
    .expect("global document not set")
    .get_element_by_id("mousemoveme")
    .expect("element with id `mousemoveme` not present")
    .unchecked_into::<HtmlElement>()
    .set_onmousemove(mousemove.as_ref().dyn_ref());

// we now need to save the `mousemove` Closure so that when
// this event fires the closure is still in memory.
```

View on GitHub (pinned to 0e4a05472f)

Solutions

  1. Use e.current_target() - the element the listener is bound to - which is always present during dispatch
  2. Guard with if let Some(target) = e.target()
  3. When synthesizing events in tests, dispatch them from a real element so target is set
  4. Treat the snippet as a starting point and add Option handling before shipping

Example fix

// before
let rect = e.target()
    .expect("mouse event doesn't have a target")
    .dyn_into::<HtmlElement>().unwrap()
    .get_bounding_client_rect();

// after: the element the listener is attached to - no Option panic
let rect = e.current_target()
    .dyn_into::<HtmlElement>()
    .expect("listener is bound to an HtmlElement")
    .get_bounding_client_rect();
Defensive patterns

Strategy: type-guard

Type guard

fn mousemove_element(e: &web_sys::MouseEvent) -> Option<web_sys::Element> {
    e.current_target().and_then(|t| t.dyn_into::<web_sys::Element>().ok())
}

Prevention

When it happens

Trigger: 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.

Common situations: Simulating pointer movement in tests; automation scripts synthesizing events; copy-pasted tutorial code later pointed at different event sources.

Related errors


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