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:
- Element nodes into opening and closing XML tags (e.g.,
<path>,<rect>). - Attribute nodes into standard XML attribute key-value pairs (e.g.,
d="...",fill="..."). - Text nodes into standard character data, escaping reserved XML
entities (
<,>,&,",') where necessary.
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);
}