File Download using JavaScript: Various Techniques and Best Practices
Learn various techniques for implementing file downloads in the browser using JavaScript.
Implementing file downloads in the browser using JavaScript can be achieved through different methods depending on the source of the data and the desired user experience.
- Key techniques include using Blob URLs, anchor tags with the download attribute, and handling binary data from APIs.
Background/Problem
While the server usually handles file delivery, the client often needs to trigger downloads for:
- Dynamically generated content (e.g., CSV, JSON) created in the browser.
- Files fetched via AJAX/Fetch that need to be saved locally.
Core Concepts
1) The Anchor Tag (<a>) Download Attribute
Modern browsers support the download attribute on <a> tags, which tells the browser to download the linked resource instead of navigating to it.
const link = document.createElement('a');\nlink.href = 'path/to/file';\nlink.download = 'filename.ext';\ndocument.body.appendChild(link);\nlink.click();\ndocument.body.removeChild(link);→ Expected Result / What Changed:
The browser automatically starts downloading the file with the name provided in the attribute.
2) Using Blob and Object URLs
For data generated on the fly, you can create a Blob (Binary Large Object) and represent it as a temporary URL.
const content = \"Hello, World!\";\nconst blob = new Blob([content], { type: 'text/plain' });\nconst url = URL.createObjectURL(blob);\n\nconst a = document.createElement('a');\na.href = url;\na.download = 'hello.txt';\na.click();\n\nURL.revokeObjectURL(url); // Clean up memoryRemember to use URL.revokeObjectURL(url) to avoid memory leaks after the download is initiated.
Solution Approach
- Direct Link: Use a simple
<a>tag for static files. - Client-side Generation: Use
BlobandURL.createObjectURL. - API Data: Fetch as
blob()then use the anchor tag hack.
Implementation (Code)
Example of downloading a file after fetching it from an API:
fetch('/api/download')\n .then(res => res.blob())\n .then(blob => {\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = 'file.pdf';\n a.click();\n URL.revokeObjectURL(url);\n });→ Expected Result / What Changed:
This allows you to customize the filename or perform authentication before starting the download.
Reproducing in Next.js (Execution via Button on Client)
\"use client\"\n\nexport default function DownloadDemo() {\n const downloadText = () => {\n const blob = new Blob([\"Hello from Next.js!\"], { type: 'text/plain' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = 'demo.txt';\n a.click();\n URL.revokeObjectURL(url);\n };\n\n return (\n <div>\n <button onClick={downloadText}>Download generated.txt</button>\n </div>\n );\n}This demonstrates how to initiate a download purely from client-side logic in a Next.js environment.