File Upload

Uploading files with progress tracking

File uploads use FormData with multipart/form-data encoding. You can upload single files, multiple files, or files with additional form fields.

For progress tracking, you need to use XMLHttpRequest since the Fetch API doesn't support upload progress (only download).

Basic File Upload with fetch()

// Single file upload const fileInput = document.querySelector('input[type="file"]'); const file = fileInput.files[0]; const formData = new FormData(); formData.append('file', file); formData.append('description', 'My uploaded file'); const response = await fetch('/api/upload', { method: 'POST', body: formData // Don't set Content-Type - browser adds boundary }); const result = await response.json(); console.log('Upload complete:', result); // Multiple files const files = fileInput.files; // FileList const formData = new FormData(); for (const file of files) { formData.append('files', file); // Same key for multiple }

Upload with Progress (XMLHttpRequest)

function uploadWithProgress(file, url, onProgress) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); const formData = new FormData(); formData.append('file', file); // Track upload progress xhr.upload.addEventListener('progress', (e) => { if (e.lengthComputable) { const percent = (e.loaded / e.total) * 100; onProgress(percent); } }); // Handle completion xhr.addEventListener('load', () => { if (xhr.status >= 200 && xhr.status < 300) { resolve(JSON.parse(xhr.responseText)); } else { reject(new Error(`HTTP ${xhr.status}`)); } }); // Handle errors xhr.addEventListener('error', () => { reject(new Error('Network error')); }); xhr.addEventListener('abort', () => { reject(new Error('Upload cancelled')); }); xhr.open('POST', url); xhr.send(formData); }); } // Usage try { const result = await uploadWithProgress( file, '/api/upload', (percent) => { progressBar.style.width = `${percent}%`; } ); console.log('Uploaded:', result); } catch (error) { console.error('Upload failed:', error); }

File Validation

function validateFile(file, options = {}) { const { maxSize = 5 * 1024 * 1024, // 5MB default allowedTypes = [], allowedExtensions = [] } = options; const errors = []; // Check file size if (file.size > maxSize) { const maxMB = (maxSize / 1024 / 1024).toFixed(1); errors.push(`File too large. Max size: ${maxMB}MB`); } // Check MIME type if (allowedTypes.length && !allowedTypes.includes(file.type)) { errors.push(`Invalid file type: ${file.type}`); } // Check extension if (allowedExtensions.length) { const ext = file.name.split('.').pop().toLowerCase(); if (!allowedExtensions.includes(ext)) { errors.push(`Invalid extension: .${ext}`); } } return { valid: errors.length === 0, errors }; } // Usage const validation = validateFile(file, { maxSize: 10 * 1024 * 1024, // 10MB allowedTypes: ['image/jpeg', 'image/png', 'image/gif'], allowedExtensions: ['jpg', 'jpeg', 'png', 'gif'] }); if (!validation.valid) { alert(validation.errors.join('\n')); return; }

Try It Live

Select a file to see what would be uploaded