Sitemap
Active Developement

Active Development technical blog, where anyone from the company can share tutorials, tips and thoughts

Handling Blob URLs in JavaScript: A Better Way to Preview and Download PDFs

--

Javascript — Blob — PDF
Javascript — Blob — PDF

Working with the Blob API in JavaScript is often a pain for developers, especially when trying to provide a user-friendly experience for file previews. A common problem is that when opening a PDF in a new tab using a blob URL, the browser displays a randomly generated string instead of a meaningful filename. This makes the user experience frustrating to say the least. In this article, we’ll explore why this happens and present a solution that improves both previewing and downloading while overcoming the limitations of blob URLs.

What is a Blob URL?

A Blob (Binary Large Object) in JavaScript represents raw binary data. The Blob API allows developers to create object URLs for temporary access to these files. When a blob is created, a unique blob URL is generated, such as:

blob:http://localhost:3000/85cad96e-e44e-a1f9-db97a96ed3fe

This URL is only valid within the current browser session and cannot be shared or accessed outside of it. When a PDF is opened using a blob URL, the browser does not have a meaningful filename to display, which can lead to a poor user experience.

Why is Previewing Blobs Difficult?

There are several key issues with blob URLs:

  1. Lack of meaningful filenames: The generated URL does not include the original file name.
  2. Non-shareable URLs: Blob URLs are only valid during the session and cannot be copied and opened later.
  3. Download naming issues: If users attempt to download the file using the browser’s default download button, the filename will appear as a random hash instead of the expected name.
  4. Limited control over UI customization: When opening the blob directly, customization options for controls, buttons, or branding are limited.

Backend Approach vs. Client-Side Approach

Of course, we can handle this on the backend by serving a file with its own URL and the correct headers. This would allow the browser to handle the file naturally, displaying the correct filename and making the file accessible via a shareable URL. However, in most modern Single Page Applications (SPAs), we generate the PDF on the client side using libraries like PDF.js. Because of this, we need a better option for previewing PDFs when a backend-generated URL is not available.

Opening a Blob URL in a New Tab looks like this

PDF open in browser tab
PDF open in browser tab

The browser will treat it as a normal PDF file with the only difference being that the filename and the URL are not something readable because the blob API does not provide a way to give it a name.

A Better Solution: Embedding the Blob in a New Tab with a Custom UI

PDF open on an iFrame in the new browser tab
PDF open on an iFrame in the new browser tab

Instead of directly opening the blob URL, we can open a new tab containing an iframe that displays the file. This allows us to:

  • Set a custom filename in the page title and history.
  • Provide a custom download button that correctly names the file.
  • Enhance the UI/UX with custom styling and functionality.

JavaScript Implementation

Here’s how you can achieve this:

function previewFile(response, filename, type = 'application/pdf') {
const file = new Blob([response.data], { type });
const fileURL = URL.createObjectURL(file);

// Open a new tab with the preview
const newTab = window.open();
if (newTab) {
newTab.document.write(`
<html>
<head>
<title>${filename}</title>
<style>
body { margin: 0; padding: 0; }
.download-btn {
position: fixed;
bottom: 20px;
right: 20px;
background-color: #007bff;
color: white;
border: none;
padding: 10px 15px;
font-size: 14px;
border-radius: 5px;
cursor: pointer;
}
.download-btn:hover {
background-color: #0056b3;
}
</style>
</head>
<body>
<iframe src="${fileURL}" style="width:100vw; height:100vh; border:none;"></iframe>
<button class="download-btn" onclick="downloadFile()">Download</button>
<script>
function downloadFile() {
const a = document.createElement('a');
a.href = "${fileURL}";
a.download = "${filename}";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
// Change the URL displayed in the address bar
window.history.pushState("", "${filename}", "/preview/${filename}");
</script>
</body>
</html>
`);
newTab.document.close();
} else {
// Gracefully handle the case if the browser stops the modal
alert("Pop-up blocked! Please allow pop-ups for this site.");
}
}

Explanation of the Solution

Creates a Blob URL:

  • Converts the response data into a Blob and generates a URL for it.

Opens a new tab:

  • Instead of opening the blob directly, a new blank tab is created.

Injects an iframe with the file preview:

  • The iframe takes up the full width and height, ensuring a seamless preview experience.

Adds a custom download button:

  • Clicking the button triggers a download with the correct filename.

Updates the browser’s URL:

  • Uses window.history.pushState to set a user-friendly URL in the address bar.

Pros and Cons of This Approach

Pros:

✅ Meaningful URL in the address bar

✅ Correct filename when downloading via the custom button

✅ Full control over the UI with HTML, CSS, and JavaScript

✅ You can even place your button over the default button for better UX

✅ Works in most modern browsers

Cons:

❌ The new URL is visual only — bookmarking or refreshing the page won’t reload the document.

❌ If users download using the browser’s default button, the filename will still be a blob hash.

❌ Browser compatibility for window.history.pushState should be checked.

Conclusion

By embedding the blob inside an iframe within a new tab, we can significantly improve the user experience when previewing and downloading PDFs. While it doesn’t solve all the issues with blob URLs, it provides a much cleaner and more intuitive interface. Hopefully, future browser updates will introduce better native support for handling blob URLs with custom filenames, but until then, this solution offers a practical workaround.

Have you found other ways to improve blob handling in JavaScript? Share your thoughts in the comments!

--

--

Active Developement
Active Developement

Published in Active Developement

Active Development technical blog, where anyone from the company can share tutorials, tips and thoughts

Houssem Guemer
Houssem Guemer

No responses yet