Downloading generated content from the client browser

25 Jun 2018

I am usually a backend (Python) developer. This javascript hint could very probably be improved and modernized. But the code works for me as is, so feel free to try it.

Sometimes, in the course of web development, there are situations where we have content that is generated by the client browser, but the user might like to download it for use offline. Specifically, graphic elements such as svg or canvas might be prime candidates for this kind of technique.

Downloading a server-generated image is dead easy: just provide an appropriate link to the generated image file on the server.

But when dealing with content that’s inside the document the user is currently looking at, things are a bit more complicated, since it’s not immediately clear where exactly the browser would be downloading the image from. Not only that, but the data the browser would be downloading is within the current document, which would be destroyed when the browser navigates away to the “download.” It seems a bit of a Catch-22.

Fortunately, there are ways to work around this. First let’s define a function that will enable us to download content on the fly, if we have a string that contains the data in question:

var saveInline = function(filename, data, mimetype='application/octet-stream') {
    var blob = new Blob([data], {type: mimetype});
    if (window.navigator.msSaveOrOpenBlob) {
        window.navigator.msSaveBlob(blob, filename);
    else {
        var elem = window.document.createElement('a');
        elem.href = window.URL.createObjectURL(blob); = filename;        

This code works by creating a phantom A tag, making our data the target of this element, and then programmatically “clicking” the link. (We also make sure to remove the phantom element after the download.)

Now we can create a function that will grab the data of an HTML element and make it into a string that we can pass to the download function:

var saveInlineElement = function(element, filename, mimetype) {
    let elContent = element.toDataURL(mimetype);
    saveInline(filename, elContent, mimetype);
    return elContent;

The If we drop these two functions into a file (named, perhaps, saveInline.js), we can then call them from an HTML page such as the following very minimal example:

<!DOCTYPE html>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width; initial-scale=1">
    <div id="svgwrapper">
        <svg xmlns="" width="64" height="64" viewBox="0 0 64 64"><circle fill="#4FD1D9" cx="32" cy="32" r="30"/><path fill="#FFF" d="M38 12L18 32l20 20z"/></svg>
        <button onclick="doDownload();">Download</button>
    <script src="saveInline.js"></script>
        var doDownload = function() {
            let el = document.querySelector("div#svgwrapper>svg");
            saveInlineElement(el, "el.svg", "text/svg");


You’ll note that there may be a restriction on saving the contents of a canvas tag this way if there have been any images drawn onto that canvas which were loaded from another domain than the one the page is hosted on. You might get a security error in this case. Take a look at Cross-Origin Resource Sharing (CORS) for more details on this kind of thing.

This code works for me with both canvas and svg elements, with modern browsers. I don’t guarantee it will work with any particular browser, especially older ones. Caveat developor. 😉


Quick topics list