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
- Ensure Portal rendering only runs client-side in a browser with a live document.
- In tests use an environment that supports createElement (jsdom document with window, or a browser test runner).
- Gate the component behind a client-only boundary (CreateEffect/mount callback rather than SSR render).
- 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
- Only render Portal in a browser with a live document
- Use browser-based test runners for DOM components
- Render server-side placeholders instead of Portal during SSR
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
- body to exist
- SVG element creation to work
- there to be a <body> element
- there to be a <html> element
- missing <head> element
AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01).
Data as JSON: /api/errors/dbeb92cb24ae3687.
Report an issue: GitHub.