leptos-rs/leptos · error
no `finished` property on ViewTransition
Error message
no `finished` property on ViewTransition
What it means
During navigation the router uses the browser's View Transitions API and reads `viewTransition.finished` via `Reflect::get`, expecting a Promise. If the returned object does not expose `finished` (unsupported/partially implemented browser, or a mocked/undefined return from `document.startViewTransition`), the `expect` panics.
Source
Thrown at router/src/lib.rs:192
if is_back_navigation {
_ = class_list.add_1("router-back");
}
match svt {
Ok(svt) => {
let cb = Closure::once_into_js(Box::new(move || {
fun();
}));
match svt.call1(
document.unchecked_ref(),
cb.as_ref().unchecked_ref(),
) {
Ok(view_transition) => {
let class_list = document_element.class_list();
let finished = Reflect::get(
&view_transition,
&JsValue::from_str("finished"),
)
.expect("no `finished` property on ViewTransition")
.unchecked_into::<Promise>();
let cb = Closure::new(Box::new(move |_| {
if is_back_navigation {
class_list.remove_1("router-back").unwrap();
}
class_list
.remove_1(&format!("router-outlet-{level}"))
.unwrap();
})
as Box<dyn FnMut(JsValue)>);
_ = finished.then(&cb);
cb.into_js_value();
}
Err(e) => {
web_sys::console::log_1(&e);
}
}
}View on GitHub (pinned to 32d20f6c9d)
Solutions
- Feature-detect full support and disable view transitions when unavailable: check `document.startViewTransition` exists and that the result has a `finished` property before using it.
- Update/avoid the problematic browser or test environment; use a real browser with complete View Transitions support.
- Remove/condition the `transition` NavigateOptions so navigation falls back to non-view-transition rendering.
Example fix
// before
let support = document.start_view_transition.is_some();
navigate_with_options("/next", NavigateOptions { transition: true, .. });
// after
let vt_ok = js!(return !!(document.startViewTransition &&
document.startViewTransition(() => {}).finished);).is_truthy();
NavigateOptions { transition: vt_ok, ..Default::default() } Defensive patterns
Strategy: type-guard
Validate before calling
// Detect full View Transitions support before enabling:
let vt_supported = window()
.and_then(|w| w.get("document").ok())
.map(|d| d.get("startViewTransition").map(|f| f.is_function()).unwrap_or(false))
.unwrap_or(false); Type guard
fn supports_view_transitions() -> bool {
window().map(|w| Reflect::has(&w, &"document".into())).unwrap_or(false)
&& js!(return typeof document.startViewTransition === "function";).is_truthy()
} Try / catch
// Wrap view-transition navigation:
if supports_view_transitions() {
navigate_with_options(path, NavigateOptions { transition: true, ..Default::default() });
} else {
navigate(path);
} Prevention
- Feature-detect View Transitions API before enabling the `transition` option.
- Avoid enabling view transitions in tests/headless environments without support.
- Track browser support matrix for the View Transitions API.
When it happens
Trigger: Navigating with `ViewTransition` enabled in a browser whose `document.startViewTransition` returns an object lacking `finished`; environments (older Safari/Firefox versions, some webviews, jsdom/test setups) with incomplete View Transitions support.
Common situations: Enabling view transitions globally and testing on a browser or headless environment without full API support; polyfills or shims that return a stub instead of a real ViewTransition; partial implementations that expose startViewTransition but not the finished promise.
Related errors
- there to be a <body> element
- there to be a <html> element
- Executor::spawn called, but no global 'spawn' function is co
- Executor::spawn_local called, but no global 'spawn_local' fu
- {location:?} expected context of type {type_name:?} to be pr
AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01).
Data as JSON: /api/errors/52ced375b77dca74.
Report an issue: GitHub.