<script type="module" src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"></script>
<script nomodule src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"></script>
<div class="container">
<h1>Download File from URL</h1>
<p class="subtitle">Enter a URL to download files directly from JavaScript</p>
<div class="demo-section">
<h2>
<ion-icon name="cloud-download-outline"></ion-icon>
Custom URL Download
</h2>
<div class="input-group">
<label>Enter File URL:</label>
<input type="text" id="fileUrl" placeholder="https://example.com/file.pdf">
</div>
<div class="input-group">
<label>Custom Filename (optional):</label>
<input type="text" id="fileName" placeholder="my-file.pdf">
</div>
<button class="btn" id="downloadBtn">
<ion-icon name="download-outline"></ion-icon>
Download File
</button>
<div class="status-message" id="statusMessage"></div>
</div>
<div class="demo-section">
<h2>
<ion-icon name="flash-outline"></ion-icon>
Quick Download Examples
</h2>
<p style="font-size: 14px; color: #666; margin-bottom: 15px;">
Click to download sample files (These are example placeholders)
</p>
<div class="quick-links">
<div class="quick-link" data-type="image">
<ion-icon name="image-outline"></ion-icon>
<p>Sample Image</p>
</div>
<div class="quick-link" data-type="text">
<ion-icon name="document-text-outline"></ion-icon>
<p>Text File</p>
</div>
<div class="quick-link" data-type="json">
<ion-icon name="code-outline"></ion-icon>
<p>JSON Data</p>
</div>
<div class="quick-link" data-type="csv">
<ion-icon name="grid-outline"></ion-icon>
<p>CSV File</p>
</div>
</div>
</div>
<div class="info-box">
<h3>
<ion-icon name="code-slash-outline"></ion-icon>
Code Examples
</h3>
<div class="code-block">
<span class="comment">// Method 1: Simple download with link</span>
<span class="keyword">function</span> <span class="function">downloadFile</span>(url, filename) {
<span class="keyword">const</span> link = document.<span class="function">createElement</span>(<span class="string">'a'</span>);
link.href = url;
link.download = filename;
link.<span class="function">click</span>();
}
<span class="comment">// Method 2: Download with fetch (for same-origin files)</span>
<span class="keyword">async function</span> <span class="function">downloadWithFetch</span>(url, filename) {
<span class="keyword">const</span> response = <span class="keyword">await</span> <span class="function">fetch</span>(url);
<span class="keyword">const</span> blob = <span class="keyword">await</span> response.<span class="function">blob</span>();
<span class="keyword">const</span> blobUrl = URL.<span class="function">createObjectURL</span>(blob);
<span class="keyword">const</span> link = document.<span class="function">createElement</span>(<span class="string">'a'</span>);
link.href = blobUrl;
link.download = filename;
link.<span class="function">click</span>();
URL.<span class="function">revokeObjectURL</span>(blobUrl);
}
<span class="comment">// Method 3: Download generated content</span>
<span class="keyword">function</span> <span class="function">downloadGeneratedFile</span>(content, filename, type) {
<span class="keyword">const</span> blob = <span class="keyword">new</span> <span class="function">Blob</span>([content], { type });
<span class="keyword">const</span> url = URL.<span class="function">createObjectURL</span>(blob);
<span class="keyword">const</span> link = document.<span class="function">createElement</span>(<span class="string">'a'</span>);
link.href = url;
link.download = filename;
link.<span class="function">click</span>();
URL.<span class="function">revokeObjectURL</span>(url);
}
</div>
</div>
<div class="info-box">
<h3>
<ion-icon name="information-circle-outline"></ion-icon>
Important Notes
</h3>
<ul>
<li><strong>CORS Policy:</strong> Downloads from external URLs may be blocked by CORS policy</li>
<li><strong>Same-Origin:</strong> Fetch method works best for files on the same domain</li>
<li><strong>Generated Content:</strong> You can create and download files dynamically using Blob</li>
<li><strong>Browser Support:</strong> The download attribute works in all modern browsers</li>
<li><strong>Security:</strong> Always validate URLs before downloading</li>
</ul>
</div>
</div>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.container {
background: white;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
padding: 50px 40px;
width: 100%;
max-width: 700px;
}
h1 {
font-size: 32px;
color: #333;
margin-bottom: 10px;
font-weight: 600;
text-align: center;
}
.subtitle {
color: #666;
font-size: 15px;
margin-bottom: 40px;
text-align: center;
}
.demo-section {
background: #f8f9fa;
border-radius: 12px;
padding: 30px;
margin-bottom: 25px;
}
.demo-section h2 {
font-size: 20px;
color: #f5576c;
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 10px;
}
.input-group {
margin-bottom: 20px;
}
.input-group label {
display: block;
font-size: 14px;
font-weight: 600;
color: #333;
margin-bottom: 8px;
}
input[type="text"] {
width: 100%;
padding: 14px;
font-size: 15px;
border: 2px solid #e0e0e0;
border-radius: 10px;
transition: border-color 0.3s;
font-family: 'Courier New', monospace;
}
input[type="text"]:focus {
outline: none;
border-color: #f5576c;
}
.btn {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
border: none;
border-radius: 10px;
padding: 14px 28px;
font-size: 15px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 10px;
width: 100%;
justify-content: center;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(245, 87, 108, 0.4);
}
.btn:active {
transform: translateY(0);
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none;
}
.quick-links {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-top: 20px;
}
.quick-link {
background: white;
border: 2px solid #e0e0e0;
border-radius: 10px;
padding: 15px;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
}
.quick-link:hover {
border-color: #f5576c;
transform: translateY(-2px);
}
.quick-link ion-icon {
font-size: 32px;
color: #f5576c;
margin-bottom: 8px;
}
.quick-link p {
font-size: 14px;
color: #666;
font-weight: 600;
}
.code-block {
background: #2d2d2d;
color: #f8f8f2;
padding: 20px;
border-radius: 10px;
font-family: 'Courier New', monospace;
font-size: 13px;
overflow-x: auto;
margin: 20px 0;
line-height: 1.8;
}
.code-block .keyword {
color: #ff79c6;
}
.code-block .string {
color: #f1fa8c;
}
.code-block .comment {
color: #6272a4;
}
.code-block .function {
color: #50fa7b;
}
.info-box {
background: #fff0f5;
border-left: 4px solid #f5576c;
padding: 20px;
border-radius: 8px;
margin: 20px 0;
}
.info-box h3 {
color: #f5576c;
margin-bottom: 10px;
font-size: 18px;
display: flex;
align-items: center;
gap: 8px;
}
.info-box ul {
margin-left: 20px;
color: #555;
line-height: 1.8;
}
.info-box li {
margin: 8px 0;
}
.status-message {
padding: 15px;
border-radius: 10px;
margin-top: 15px;
font-size: 14px;
font-weight: 500;
display: none;
}
.status-success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
display: flex;
align-items: center;
gap: 10px;
}
.status-error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
display: flex;
align-items: center;
gap: 10px;
}
.status-info {
background: #d1ecf1;
color: #0c5460;
border: 1px solid #bee5eb;
display: flex;
align-items: center;
gap: 10px;
}
.download-list {
background: white;
border-radius: 10px;
padding: 20px;
margin-top: 20px;
}
.download-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 15px;
border-bottom: 1px solid #e0e0e0;
}
.download-item:last-child {
border-bottom: none;
}
.download-info {
display: flex;
align-items: center;
gap: 12px;
}
.download-info ion-icon {
font-size: 24px;
color: #f5576c;
}
.download-details p {
font-size: 14px;
color: #333;
font-weight: 600;
}
.download-details span {
font-size: 12px;
color: #999;
}
.download-btn {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
border: none;
border-radius: 8px;
padding: 8px 16px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 6px;
}
.download-btn:hover {
transform: scale(1.05);
}
const fileUrlInput = document.getElementById('fileUrl');
const fileNameInput = document.getElementById('fileName');
const downloadBtn = document.getElementById('downloadBtn');
const statusMessage = document.getElementById('statusMessage');
const quickLinks = document.querySelectorAll('.quick-link');
// Function to download file from URL
function downloadFile(url, filename) {
try {
const link = document.createElement('a');
link.href = url;
link.download = filename || 'download';
link.target = '_blank';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
return true;
} catch (error) {
console.error('Download error:', error);
return false;
}
}
// Function to download generated content
function downloadGeneratedFile(content, filename, mimeType) {
const blob = new Blob([content], { type: mimeType });
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);
}
// Show status message
function showStatus(message, type) {
statusMessage.textContent = message;
statusMessage.className = `status-message status-${type}`;
statusMessage.style.display = 'flex';
setTimeout(() => {
statusMessage.style.display = 'none';
}, 5000);
}
// Custom URL download
downloadBtn.addEventListener('click', () => {
const url = fileUrlInput.value.trim();
const filename = fileNameInput.value.trim();
if (!url) {
showStatus('⚠️ Please enter a valid URL', 'error');
return;
}
// Validate URL
try {
new URL(url);
} catch (e) {
showStatus('⚠️ Invalid URL format', 'error');
return;
}
const success = downloadFile(url, filename);
if (success) {
showStatus('✓ Download started successfully!', 'success');
} else {
showStatus('⚠️ Download failed. Check console for details.', 'error');
}
});
// Quick download examples
quickLinks.forEach(link => {
link.addEventListener('click', () => {
const type = link.getAttribute('data-type');
switch(type) {
case 'image':
// Generate a simple SVG image
const svgContent = `<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<rect width="200" height="200" fill="#f093fb"/>
<text x="100" y="100" text-anchor="middle" fill="white" font-size="20">Sample Image</text>
</svg>`;
downloadGeneratedFile(svgContent, 'sample-image.svg', 'image/svg+xml');
showStatus('✓ Sample image downloaded!', 'success');
break;
case 'text':
const textContent = 'This is a sample text file downloaded using JavaScript!\n\nYou can download any text content this way.';
downloadGeneratedFile(textContent, 'sample-text.txt', 'text/plain');
showStatus('✓ Text file downloaded!', 'success');
break;
case 'json':
const jsonContent = JSON.stringify({
name: 'Sample Data',
type: 'JSON',
created: new Date().toISOString(),
data: [1, 2, 3, 4, 5]
}, null, 2);
downloadGeneratedFile(jsonContent, 'sample-data.json', 'application/json');
showStatus('✓ JSON file downloaded!', 'success');
break;
case 'csv':
const csvContent = 'Name,Email,Age\nJohn Doe,john@example.com,30\nJane Smith,jane@example.com,25\nBob Johnson,bob@example.com,35';
downloadGeneratedFile(csvContent, 'sample-data.csv', 'text/csv');
showStatus('✓ CSV file downloaded!', 'success');
break;
}
});
});
// Allow Enter key to trigger download
fileUrlInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
downloadBtn.click();
}
});
No comments yet. Be the first!