leptos-rs/leptos · error

HTML element creation to work

Error message

HTML element creation to work

What it means

The non-SVG branch of Portal creates its container with document().create_element("div") and expects success. Like the SVG case, this fails only when the runtime environment cannot create HTML elements — no real document attached (workers, tests without DOM).

Source

Thrown at leptos/src/portal.rs:52

            .unwrap_or(true)
    {
        use send_wrapper::SendWrapper;
        use wasm_bindgen::JsCast;

        let mount = mount.unwrap_or_else(|| {
            document().body().expect("body to exist").unchecked_into()
        });
        let children = children.into_inner();

        Effect::new(move |_| {
            let container = if is_svg {
                document()
                    .create_element_ns(Some("http://www.w3.org/2000/svg"), "g")
                    .expect("SVG element creation to work")
            } else {
                document()
                    .create_element("div")
                    .expect("HTML element creation to work")
            };

            let render_root = if use_shadow {
                container
                    .attach_shadow(&web_sys::ShadowRootInit::new(
                        web_sys::ShadowRootMode::Open,
                    ))
                    .map(|root| root.unchecked_into())
                    .unwrap_or(container.clone())
            } else {
                container.clone()
            };

            let _ = mount.append_child(&container);
            let handle = SendWrapper::new((
                mount::mount_to(render_root.unchecked_into(), {
                    let children = Arc::clone(&children);
                    move || untrack(|| children())

View on GitHub (pinned to 32d20f6c9d)

Solutions

  1. Ensure Portal rendering only runs client-side in a browser with a live document.
  2. In tests use an environment that supports createElement (jsdom document with window, or a browser test runner).
  3. Gate the component behind a client-only boundary (CreateEffect/mount callback rather than SSR render).
  4. If SSR is required, render placeholder markup instead of Portal on the server.

Example fix

// before
#[test]
fn renders_portal() { /* jsdom-less: create_element fails */ }
// after
#[wasm_bindgen_test]
fn renders_portal() { /* browser test runner: real document */ }
Defensive patterns

Strategy: validation

Validate before calling

if document().create_element("div").is_err() {
    // DOM unavailable: skip Portal rendering
    return;
}

Type guard

fn dom_available() -> bool {
    document().create_element("div").is_ok()
}

Prevention

When it happens

Trigger: Rendering a Portal (default HTML children) inside a web worker, SSR code path, or test harness where document().create_element returns Err.

Common situations: Calling Portal-rendering components from server code; wasm tests without a DOM; exotic webviews without DOM support.

Related errors


AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01). Data as JSON: /api/errors/dbeb92cb24ae3687. Report an issue: GitHub.