yewstack/yew · error

event target should be of type HtmlElement

Error message

event target should be of type HtmlElement

What it means

This panic is `.dyn_into::<HtmlElement>().expect("event target should be of type HtmlElement")` in Yew 0.23's web-sys mousemove example. `JsCast::dyn_into` returns `Err(EventTarget)` when the target is not an `HtmlElement` JS instance. `e.target()` is the deepest node under the pointer, so the cast fails when the listener is bound to `document`/`window` (target is a Document/Window) or when the pointer is over an SVG descendant (target is `SvgElement`).

Source

Thrown at website/versioned_docs/version-0.23/concepts/basic-web-technologies/web-sys.mdx:174

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: MouseEvent| {
    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.
```

This version is much more verbose, but you will probably notice part of that is because of failure

View on GitHub (pinned to 0e4a05472f)

Solutions

  1. Use `target.dyn_ref::<HtmlElement>()` in an `if let` and skip non-HTML-element targets
  2. Use `e.current_target()` — the element the handler is attached to — so the `HtmlElement` cast always succeeds
  3. When listening on document by design, `match` on `dyn_into` and handle both arms

Example fix

// before
.dyn_into::<HtmlElement>()
.expect("event target should be of type HtmlElement")
.get_bounding_client_rect();

// after
let rect = e
    .current_target()
    .dyn_into::<HtmlElement>()
    .ok()?
    .get_bounding_client_rect();
Defensive patterns

Strategy: type-guard

Validate before calling

let t = e.current_target();
if !t.is_instance_of::<web_sys::HtmlElement>() {
    return;
}
let rect = t.unchecked_ref::<web_sys::HtmlElement>().get_bounding_client_rect();

Type guard

use wasm_bindgen::JsCast;
use web_sys::{EventTarget, HtmlElement};

fn is_html_element(t: &EventTarget) -> bool {
    t.is_instance_of::<HtmlElement>()
}

Prevention

When it happens

Trigger: Binding `onmousemove` on `document` or `window` for full-page tracking; pointer hovering `<svg>`/`<canvas>`/MathML children whose JS type is not HtmlElement; synthetic events dispatched on the document node.

Common situations: Extending the guide's snippet to page-level tracking; icon-heavy layouts inside the tracked element; test dispatch on non-element nodes.

Related errors


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