javascriptwindow.opendata-uri

Opening a computed document using window.open() and data: scheme


I have a webpage running in a browser that generates a computed HTML document, and I want to open that document in a new browser tab.

The simple and dirty method is to do this:

const w = window.open('', '_blank');
w.document.open();
w.document.write(htmlContents);
w.document.close();

Easy enough. But this has some awkward consequences that I do not like. Namely, the URL of the new tab has to point somewhere, but there is nowhere to point it at since the new document is computed on the fly. If I specify no URL, it uses the URL of my webpage. So if someone refreshed the tab containing the generated document, the document disappears and a new instance of my webpage loads in its place. This would be confounding to the user.

What I believe better suits my needs is to use a data URI instead. I would simply encode the entire contents of my webpage into the URI itself, and use window.open() to open that URI. It's ugly, but semantically aligned with my goal: a standalone computed document that can't accidentally be navigated out of due to page refreshing.

I constructed what I thought was a trivially simple concept for this, like so:

const doc = encodeURIComponent('<html><body><p>Hello, world!</p></body></html>');
window.open(`data:text/html;charset=utf-8,${doc}`, '_blank');

If I run this code, a new window flashes on my screen for one frame before immediately closing. No error raised.

What am I doing incorrectly?


Solution

  • Apparently all modern browsers have explicitly blocked this use of Data URIs on purpose. Wonderful.

    Another tick on the chalkboard for "the singular very perfect thing I needed was taken away from us relatively recently". Ugh.

    On the bright side, this seems to do everything I want even better:

    const html = '<html><body><p>Hello, world!</p></body></html>';
    const blob = new Blob([html], { type: 'text/html'});
    const url = URL.createObjectURL(blob);
    window.open(url, '_blank');