dotnet/aspnetcore · error · Error
Unable to focus an SVG element that does not have a tabindex
Error message
Unable to focus an SVG element that does not have a tabindex.
What it means
Thrown by domFunctions.focus when the target is an SVGElement without a tabindex attribute. Unlike HTMLElement, SVG elements are not focusable by default; calling .focus() on one without an explicit tabindex has no effect and is almost always a bug, so Blazor refuses rather than silently no-op.
Source
Thrown at src/Components/Web.JS/src/DomWrapper.ts:18
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
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 294cab2f9b)
Solutions
- Add tabindex="-1" (or tabindex="0") to the SVG element before focusing it.
- Wrap the SVG in a focusable container (e.g. a <button>) and focus that instead.
- Use focusBySelector with a selector that targets an HTMLElement ancestor.
- Guard the call: if (element instanceof SVGElement && !element.hasAttribute('tabindex')) return;
Example fix
// before <svg #icon></svg> await icon.FocusAsync(); // throws // after <svg #icon tabindex="-1"></svg> await icon.FocusAsync();
Defensive patterns
Strategy: type-guard
Validate before calling
function focusIfFocusable(el: HTMLOrSVGElement | null, preventScroll = false) {
if (el instanceof SVGElement && !el.hasAttribute('tabindex')) return;
if (el instanceof HTMLElement || el instanceof SVGElement) {
el.focus({ preventScroll });
}
} Type guard
function isFocusable(el: HTMLOrSVGElement | null): el is HTMLElement | SVGElement {
if (el instanceof HTMLElement) return true;
if (el instanceof SVGElement) return el.hasAttribute('tabindex');
return false;
} Try / catch
try {
Blazor._internal.domFunctions.focus(svgEl, false);
} catch (e) {
if (/does not have a tabindex/.test((e as Error).message)) {
svgEl.setAttribute('tabindex', '-1');
svgEl.focus({ preventScroll: false });
} else throw e;
} Prevention
- Always add tabindex="-1" to SVG elements you intend to focus programmatically.
- Focus an HTMLElement button wrapping the SVG instead of the SVG itself.
- Type-guard SVG elements and check for tabindex before focusing.
- Use focusBySelector on a focusable ancestor selector.
When it happens
Trigger: A @focus directive or Blazor._internal.domFunctions.focus() call targeting an SVG element (e.g. <svg>, <rect>, <circle>, <path>) that has no tabindex attribute. Common when a component tries to programmatically focus an icon or vector graphic on validation error.
Common situations: Calling FocusAsync on an ElementReference pointing at an SVG; routing focus to an SVG icon used as a button without making it focusable; accessibility tooling that walks the DOM and focuses SVG nodes.
Related errors
- Unable to focus an invalid element.
- Cannot connect component ${this.localName} to the document a
- The '${beforeElementSelector}' selector is not supported.
- Could not find any element matching selector '${elementSelec
- Could not resolve a root component with SSR component ID '${
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/cd1e374ff15e1bbe.
Report an issue: GitHub.