Convert SVG to Downloadable Markup with XMLSerializer

Exporting an in-memory SVG DOM element as a downloadable file in client-side JavaScript requires converting the live Document Object Model (DOM) tree into a well-formed XML string. The native XMLSerializer interface accomplishes this by traversing the SVG node hierarchy, resolving necessary XML namespaces, and generating standard XML text. Once serialized, this string can be encapsulated into a Blob and transformed into a downloadable asset via a temporary Object URL.

1. The DOM-to-String Serialization Process

Browsers store active SVG elements as DOM nodes in memory rather than plain text. To reconstruct raw markup, the XMLSerializer class provides the serializeToString() method:

const serializer = new XMLSerializer();
const svgString = serializer.serializeToString(svgElement);

When serializeToString() is invoked on an <svg> element, the serializer performs a recursive depth-first traversal of the element and all its descendants. During this traversal, it converts:

2. Namespace Handling

For an SVG file to render independently outside of an HTML document, it must declare its XML namespace. A standard inline <svg> element rendered in an HTML5 page may omit the xmlns attribute because the HTML parser recognizes SVG natively.

When XMLSerializer processes an SVG node, it identifies the element’s namespace URI (http://www.w3.org/2000/svg). If the root <svg> tag lacks an explicit xmlns attribute, the serializer injects xmlns="http://www.w3.org/2000/svg" into the serialized string. This ensures the output is valid, standalone XML compatible with external graphics software and image viewers.

3. Converting Serialized Markup to a Downloadable File

Once XMLSerializer produces the raw markup string, the browser must convert the text into binary data and trigger a file transfer.

Step 1: Create a Blob

Wrap the serialized string in a Blob object, specifying the MIME type as image/svg+xml:

const svgBlob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });

Step 2: Generate an Object URL

Generate a unique reference to the in-memory Blob using URL.createObjectURL():

const downloadUrl = URL.createObjectURL(svgBlob);

Step 3: Trigger the Download

Create an off-screen <a> element, assign its href to the object URL, set the download attribute with the desired filename, and programmatically click it:

const link = document.createElement('a');
link.href = downloadUrl;
link.download = 'graphic.svg';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);

Step 4: Clean Up Memory

Release the temporary object URL to free browser memory:

URL.revokeObjectURL(downloadUrl);

Summary Function

Combining these steps produces a standalone utility for exporting any rendered SVG node:

function downloadSVG(svgElement, filename = 'export.svg') {
  const serializer = new XMLSerializer();
  let source = serializer.serializeToString(svgElement);

  // Add XML declaration if not present
  if (!source.match(/^<\?xml/)) {
    source = '<?xml version="1.0" standalone="no"?>\r\n' + source;
  }

  const blob = new Blob([source], { type: 'image/svg+xml;charset=utf-8' });
  const url = URL.createObjectURL(blob);
  
  const link = document.createElement('a');
  link.href = url;
  link.download = filename;
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  
  URL.revokeObjectURL(url);
}