📁 Drag & Drop + Progress Bar, Native
No more FormData polyfills. FormData API sends forms + files with fetch. Track upload progress, handle multiple files.
📝 Basic File Upload
<input type="file" id="fileInput" multiple>
<button onclick="uploadFiles()">Upload</button>
<progress id="progressBar" value="0" max="100"></progress>
async function uploadFiles() {
const files = document.getElementById('fileInput').files;
const formData = new FormData();
for (let file of files) {
formData.append('files[]', file);
}
const response = await fetch('/upload', {
method: 'POST',
body: formData
// Don't set Content-Type — browser sets boundary automatically
});
const result = await response.json();
console.log('Uploaded:', result);
}
🎯 Upload Progress Tracking
async function uploadWithProgress(file) {
const formData = new FormData();
formData.append('file', file);
// Use XMLHttpRequest for progress events (Fetch doesn't support yet)
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable) {
const percent = (e.loaded / e.total) * 100;
updateProgressBar(percent);
}
});
xhr.onload = () => {
if (xhr.status === 200) {
resolve(JSON.parse(xhr.response));
} else {
reject(new Error('Upload failed'));
}
};
xhr.open('POST', '/upload');
xhr.send(formData);
});
}
✅ Drag & Drop Upload
const dropZone = document.getElementById('dropZone');
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.classList.add('drag-over');
});
dropZone.addEventListener('dragleave', () => {
dropZone.classList.remove('drag-over');
});
dropZone.addEventListener('drop', async (e) => {
e.preventDefault();
dropZone.classList.remove('drag-over');
const files = Array.from(e.dataTransfer.files);
const formData = new FormData();
files.forEach(file => formData.append('files[]', file));
await fetch('/upload', { method: 'POST', body: formData });
});
💡 Tips
- Don’t set
Content-Typeheader — browser sets multipart boundary - Use
formData.append('field', value, filename)for custom filenames - Access files in Node/Express:
req.files(multer middleware) - Limit file size and type on both client and server
“Removed 50KB upload library. Built custom drag-drop upload with progress in 50 lines. FormData API is all you need for 95% of use cases.”
