dotnet/aspnetcore · error · Error
Unable to focus an invalid element.
Error message
Unable to focus an invalid element.
What it means
Blazor's interop `focus` helper moves keyboard focus to a DOM element passed from .NET (e.g. via `FocusAsync`/`@ref`). It branches on `instanceof HTMLElement` then `instanceof SVGElement`; if the value matches neither branch it is treated as invalid and the call throws. In practice the element is null/undefined, a non-element node, or a detached node whose identity no longer satisfies the instanceof checks.
Solutions
- Null-check the element reference on the .NET side (`@if (myRef is not null) await myRef.FocusAsync();`) before invoking focus.
- Ensure the focused element is a real, attached HTMLElement/SVGElement — verify `.isConnected` or that the owning `@if`/`@foreach` branch is still rendered at call time.
- Prefer `focusBySelector` (CSS-selector overload) when you only have a selector: it silently no-ops when `querySelector` finds nothing instead of throwing.
- For SVG targets, add `tabindex="-1"` so the SVG branch succeeds rather than hitting the invalid/missing-tabindex errors.
Example fix
// before
const el = document.querySelector('.maybe-gone');
focus(el, false); // el is null -> 'Unable to focus an invalid element.'
// after
const el = document.querySelector('.maybe-gone');
if (el instanceof HTMLElement || el instanceof SVGElement) {
focus(el, false);
} Defensive patterns
Strategy: type-guard
Validate before calling
const el = document.querySelector(sel);
if (!el) return; // nothing matched
if (!(el instanceof HTMLElement) && !(el instanceof SVGElement)) {
throw new Error('Selector did not resolve a focusable element.');
}
focus(el, false); Type guard
function isFocusable(el: unknown): el is HTMLElement | SVGElement {
return el instanceof HTMLElement || el instanceof SVGElement;
} Try / catch
try { focus(element, preventScroll); }
catch (e) { if (/invalid element/.test(e.message)) { /* degrade silently or log */ } else throw e; } Prevention
- Null-check element references on the .NET side before FocusAsync.
- Verify element.isConnected before focusing to avoid detached nodes.
- Prefer focusBySelector when you only have a CSS selector — it no-ops on no match.
- Add tabindex to SVG elements you intend to focus programmatically.
When it happens
Trigger: Calling `domFunctions.focus(element, preventScroll)` (directly or through `FocusAsync`) when `element` is null, undefined, a text node, a Document/Window, or an element reference held by .NET that was removed during a re-render so it is no longer an HTMLElement/SVGElement at runtime.
Common situations: Focusing an element inside an `@if` block that was toggled off before the await completed; holding a stale `ElementReference` across a hot reload or navigation; passing the result of `querySelector` that returned null; focusing a component host whose underlying DOM node was replaced by diffing.
Related errors
- Could not find any element matching selector
- Could not find ' ' (' ' was undefined).
- Either assemblyName or dotNetObjectId must have a non null…
- Interop methods are already registered for renderer
- Interop methods are not registered for renderer
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/2a04c17080f08d77.
Report an issue: GitHub.
Appendix: source
Thrown at src/Components/Web.JS/src/DomWrapper.ts:21
import '@microsoft/dotnet-js-interop';
export const domFunctions = {
focus,
focusBySelector,
};
function focus(element: HTMLOrSVGElement, preventScroll: boolean): void {
if (element instanceof HTMLElement) {
element.focus({ preventScroll });
} else if (element instanceof SVGElement) {
if (element.hasAttribute('tabindex')) {
element.focus({ preventScroll });
} else {
throw new Error('Unable to focus an SVG element that does not have a tabindex.');
}
} else {
throw new Error('Unable to focus an invalid element.');
}
}
function focusBySelector(selector: string) {
const element = document.querySelector(selector) as HTMLElement;
if (element) {
// If no explicit tabindex is defined, mark it as programmatically-focusable.
// This does actually add a new HTML attribute, but it shouldn't interfere with
// diffing because diffing only deals with the attributes you have in your code.
if (!element.hasAttribute('tabindex')) {
element.tabIndex = -1;
}
element.focus({ preventScroll: true });
}
}
View on GitHub (pinned to 3600ca084e)