SVG, XHTML and XML in the browser

Inline SVG as real XML, XHTML strictness and the XML parsing mode, foreignObject for mixing vocabularies, and the namespace serialisation pitfalls that break rendering.

SVG in a page is XML

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 80" width="200" height="80">
  <title>Request latency by hour</title>
  <defs>
    <linearGradient id="fade" x1="0" y1="0" x2="0" y2="1">
      <stop offset="0" stop-color="#4c8bf5"/>
      <stop offset="1" stop-color="#4c8bf5" stop-opacity="0"/>
    </linearGradient>
  </defs>
  <rect x="0" y="0" width="200" height="80" fill="url(#fade)"/>
  <circle cx="40" cy="40" r="6" fill="#fff"/>
  <path d="M10 60 L60 30 L110 45 L160 15" fill="none" stroke="#fff" stroke-width="2"/>
</svg>
  • An inline SVG element inherits the surrounding document's namespace rules, and a standalone SVG file declares its own.
  • Attributes in SVG are case-sensitive: viewBox is not viewbox, and preserveAspectRatio is camel-cased.
  • Styling can come from CSS, but presentation attributes cannot easily be overridden by a class with equal specificity.
  • foreignObject embeds HTML content inside SVG, which needs its own namespace declaration on the child element.
<svg xmlns="http://www.w3.org/2000/svg" width="240" height="60">
  <foreignObject x="0" y="0" width="240" height="60">
    <div xmlns="http://www.w3.org/1999/xhtml" style="font: 14px sans-serif">
      Regular HTML inside SVG, with a <b>bold</b> word.
    </div>
  </foreignObject>
</svg>

Serving a page as XML

GET /page HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/xhtml+xml; charset=utf-8

<!-- parsed in XML mode: any error is a fatal parse error -->
MistakeHTML modeXHTML or XML mode
Unclosed <p>Recovered by the parserFatal parse error, page fails
Unescaped ampersandRecoveredFatal parse error
Attribute without quotesAcceptedFatal parse error
Case mismatch <DIV>IgnoredA different element in the XML model
Missing namespaceElements lose stylingElements are in no namespace, rendering fails
Invalid characterSubstitutedFatal parse error

The browser shows an error page rather than a partially rendered document, which is why most sites stay on text/html and treat well-formedness as a coding standard rather than a delivery mode.

Namespaces and serialisation pitfalls

// creating an element in the SVG namespace, not the HTML one
const NS = "http://www.w3.org/2000/svg";
const svg = document.createElementNS(NS, "svg");
const circle = document.createElementNS(NS, "circle");
circle.setAttribute("cx", "40");     // plain attributes need no namespace
circle.setAttributeNS(NS, "xlink:href", "#icon");  // namespaced attribute needs the qualified form
svg.appendChild(circle);
document.body.appendChild(svg);

// element.innerHTML on an SVG element parses in HTML mode and can lose the namespace
const text = new XMLSerializer().serializeToString(svg);
  1. Create SVG nodes with createElementNS, never createElement.
  2. Set namespaced attributes with setAttributeNS; a plain set often produces an attribute the renderer ignores.
  3. Serialising a subtree can drop a namespace declaration if the parent supplied it, producing a fragment that fails to render when reinserted.
  4. Cloning a node across documents imports nothing of the namespace map, so declare the namespace on the copied root.
  5. Data inserted as markup is script-capable. Put untrusted text in as a text node so it is escaped automatically.
💡
An inline SVG diagram is code, not an image. Content inserted into it from a user, a log file or a third-party API must be treated as untrusted and inserted as text, never as markup, or the drawing surface becomes an injection point.

FAQ

Should I serve XHTML?
Rarely. text/html with well-formed markup gives you the interoperability without the fatal-error behaviour. Use application/xhtml+xml only when you specifically need XML processing in the browser.
Why does my inline SVG render as a blank box?
Usually a missing xmlns on the root, or the element was created with createElement so it landed in the HTML namespace and has no SVG rendering.

JSON or XML today: migration and coexistence Transforming XML with XSLT templates

Last refreshed 2026-09-18.