Documentation index for AI agents (llms.txt). Markdown versions of every page are available by appending .md to the page URL. The full corpus is at /llms-full.txt.

XML & SVG Document Support

Inspector Lab adapts seamlessly to inspect XML documents and standalone SVG files opened directly in the browser. This page outlines how the inspector overcomes non-HTML document constraints by patching core DOM APIs, safely rendering its UI, and ensuring all inspection features keep working even in nonstandard document types.

The Challenge: Non-HTML Namespaces

When browsing standalone SVG or XML documents, the browser operates outside the traditional HTML namespace. This introduces several obstacles:

  • document.createElement() creates elements in the null namespace rather than HTML.
  • Created elements lack .style, cannot have attachShadow() called, and do not support CSS styling as HTML elements do.
  • UI frameworks like React and styled-components expect real HTML elements and break on XML roots.
  • The inspector's own interface—panels, overlays, highlights—cannot render without valid HTML elements.

Solution: Patching document.createElement()

To bridge this gap, the inspector patches document.createElement() at the very start of its injection process, ensuring every element it creates (including those from React and styled-components) lands in the correct namespace:

document.createElement = ((tagName: string, options?: ElementCreationOptions) =>
  document.createElementNS(
    "http://www.w3.org/1999/xhtml",
    tagName.toLowerCase(),
    options,
  )
) as typeof document.createElement;
  • This patch is only present in the inspector’s isolated execution context; page scripts never see it.
  • All inspector-created markup now renders as proper HTML, no matter the underlying document type.

Detecting HTML vs. XML/SVG

The inspector detects the host document type by checking the namespace of a test element:

export const isHtmlDom: boolean = (() => {
  try {
    return document.createElement("div").namespaceURI === "http://www.w3.org/1999/xhtml";
  } catch {
    return false;
  }
})();

This logic avoids unreliable checks like instanceof HTMLDocument.

Polyfilling document.head

Libraries such as styled-components expect document.head to exist for meta lookups and stylesheet insertion. SVG and XML documents do not have a native <head>. The inspector remedies this by defining a synthetic head:

const detachedHead = document.createElementNS("http://www.w3.org/1999/xhtml", "head");
Object.defineProperty(document, "head", {
  configurable: true,
  get: () => document.getElementById("inspector-lab-extension-layer") ?? detachedHead,
});
  • Until the inspector’s overlay is mounted, the getter returns a detached, standalone head, ensuring no null access errors even before UI loads.
  • Once bootstrapped, it returns the overlay node itself. Script or style tags appended here are live in the document.

The FOREIGN_LAYER_ID constant—set to "inspector-lab-extension-layer"—is defined in this compatibility module, which imports nothing, so the head shim can use it without dependency cycles.

The <foreignObject> Overlay Container

On SVG root documents, you cannot simply append HTML nodes to <svg>. To make the inspector UI visible, it is rendered inside a viewport-sized SVG <foreignObject> node:

export const FOREIGN_LAYER_ID = "inspector-lab-extension-layer";
  • The entire React tree and styled-components UI is hosted inside the <foreignObject> as HTML content.
  • The overlay node gets this ID, making it discoverable for the head polyfill and DOM filtering.

When the inspector is bootstrapped, this overlay root is registered for use by overlays and highlights:

export function setOverlayRoot(element: Element): void {
  overlayParent = element;
}

Overlay Positioning: Fixed vs. Absolute

In HTML, overlays are position: fixed on the viewport. In SVG/XML documents (where overlays live inside a <foreignObject>), overlays must be position: absolute in the overlay container:

export function overlayPosition(): "fixed" | "absolute" {
  return overlayParent ? "absolute" : "fixed";
}

This ensures overlays are anchored to the visible viewport in both scenarios while avoiding browser rendering bugs (e.g., WebKit issues with fixed-in-foreignObject).

Stylable Elements

Both HTMLElement and SVGElement implement CSSStyleDeclaration for their .style property:

export type StylableElement = HTMLElement | SVGElement;

This lets the inspector uniformly read and update inline styles regardless of whether the element is HTML or SVG.

Stylesheet Rule Matching

The inspector’s CSS-matching routines, such as those in matchedCssRules(), work for both HTML and SVG elements. Rule matching logic checks if an element is stylable by being either HTMLStyleElement or SVGStyleElement:

const isStyleTag =
  owner instanceof HTMLStyleElement || owner instanceof SVGStyleElement;

The APIs (document.styleSheets, CSSStyleSheet, element.matches()) are supported in both document types.

Filtering Inspector Nodes from Serialization and the Outline

To avoid self-selection and polluting copy-paste, the inspector tracks its own DOM nodes (including overlays, the <foreignObject>, and stylesheets) by a set of reserved IDs. Functions like serializeElement() use this list to remove inspector-injected nodes from exported markup:

const INSPECTOR_NODE_IDS: readonly string[] = [
  HOST_ID,
  FOREIGN_LAYER_ID,
  HIGHLIGHT_ID,
  HOVER_HIGHLIGHT_ID,
  STATE_STYLE_ID,
];

export function isInspectorNode(node: Element): boolean {
  return INSPECTOR_NODE_IDS.includes(node.id);
}

export function serializeElement(element: Element): string {
  const clone = element.cloneNode(true) as Element;
  for (const id of INSPECTOR_NODE_IDS) {
    clone.querySelector(`#${id}`)?.remove();
  }
  return clone.outerHTML;
}
  • This ensures “Copy Element” and DOM outline views do not include any of the inspector’s own UI elements, highlights, overlays, or injected styles.

Import-Order Guarantee

Critical: this compatibility patch must be imported first, ahead of React, styled-components, or any DOM utility, so that element creation is patched before other framework code runs.

// xml-compat.ts
/**
 * This module must stay the first import of the injected entry, ahead of
 * anything that might create elements.
 */

Testing Inspector Lab on SVG/XML Documents

To verify XML/SVG compatibility:

  1. Create or select a standalone SVG or XML file.
  2. Open it directly in a browser tab.
  3. Open the Inspector Lab DevTools.
  4. The full inspector UI should function: selection, highlighting, styles, markup, and “Copy Element” work as they do on HTML pages.

The inspector transparently adapts overlays, serialization, stylesheet reading, and DOM handling for both HTML and XML/SVG documents, providing a consistent experience regardless of the underlying DOM architecture.