UPL001

Drag and Drop File Upload

A modern file upload component with drag and drop functionality

JavaScript
Font Awesome Included: This snippet uses Font Awesome icons. The required stylesheet is automatically included at the top of the code block. If you are going to use this snippet in your project, add the stylesheet to your <head>.

Live Preview

Drag & Drop Files Here

or

Supports: JPG, PNG, PDF, DOC, MP4 (Max: 10MB)

Code

HTML
<!-- Font Awesome Icons; Make sure to add it in the <head> tag -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
  
<div class="file-upload-container">
  <div class="file-upload-area" id="drop-area">
    <div class="file-upload-message">
      <i class="fas fa-cloud-upload-alt"></i>
      <h3>Drag & Drop Files Here</h3>
      <p>or</p>
      <label for="fileUpload" class="file-upload-btn">Browse Files</label>
      <input type="file" id="fileUpload" multiple hidden>
      <p class="file-upload-info">Supports: JPG, PNG, PDF, DOC, MP4 (Max: 10MB)</p>
    </div>
    <div class="file-upload-preview" id="previewArea"></div>
  </div>
</div>
CSS
:root {
  --upload-bg: #f8f9fa;
  --upload-border: #e0e0e0;
  --upload-border-active: #4a6cf7;
  --upload-text: #4a4a4a;
  --upload-icon: #4a6cf7;
  --upload-btn-bg: #4a6cf7;
  --upload-btn-bg-hover: #3652cc;
  --upload-btn-text: #ffffff;
  --upload-item-bg: #ffffff;
  --upload-item-border: #e0e0e0;
  --upload-item-progress: #4a6cf7;
  --upload-item-icon: #27ae60;
  --upload-item-remove: #e74c3c;
  --upload-transition: all 0.3s ease;
}

/* Dark mode variables */
@media (prefers-color-scheme: dark) {
  :root {
    --upload-bg: #1e1e1e;
    --upload-border: #333333;
    --upload-border-active: #6c8fff;
    --upload-text: #e1e1e1;
    --upload-icon: #6c8fff;
    --upload-btn-bg: #6c8fff;
    --upload-btn-bg-hover: #5373e0;
    --upload-btn-text: #ffffff;
    --upload-item-bg: #2a2a2a;
    --upload-item-border: #333333;
    --upload-item-progress: #6c8fff;
    --upload-item-icon: #27ae60;
    --upload-item-remove: #e74c3c;
  }
}

.file-upload-container {
  width: 100%;
  max-width: 600px;
  margin: 0 auto;
}

.file-upload-area {
  position: relative;
  width: 100%;
  min-height: 250px;
  background-color: var(--upload-bg);
  border: 2px dashed var(--upload-border);
  border-radius: 10px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: 30px 20px;
  box-sizing: border-box;
  transition: var(--upload-transition);
  overflow: hidden;
}

.file-upload-area.active {
  border-color: var(--upload-border-active);
  background-color: rgba(74, 108, 247, 0.05);
}

.file-upload-message {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  color: var(--upload-text);
  width: 100%;
}

.file-upload-message i {
  font-size: 3rem;
  color: var(--upload-icon);
  margin-bottom: 1rem;
}

.file-upload-message h3 {
  margin: 0 0 0.5rem;
  font-size: 1.2rem;
}

.file-upload-message p {
  margin: 0.5rem 0;
}

.file-upload-btn {
  display: inline-block;
  padding: 10px 20px;
  margin: 10px 0;
  background-color: var(--upload-btn-bg);
  color: var(--upload-btn-text);
  border-radius: 5px;
  font-weight: 500;
  cursor: pointer;
  transition: var(--upload-transition);
}

.file-upload-btn:hover {
  background-color: var(--upload-btn-bg-hover);
}

.file-upload-info {
  font-size: 0.8rem;
  opacity: 0.7;
}

.file-upload-preview {
  width: 100%;
  margin-top: 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.upload-item {
  display: flex;
  align-items: center;
  background-color: var(--upload-item-bg);
  border: 1px solid var(--upload-item-border);
  border-radius: 5px;
  padding: 10px;
  position: relative;
}

.upload-item-icon {
  font-size: 1.5rem;
  margin-right: 15px;
}

.upload-item-details {
  flex: 1;
}

.upload-item-name {
  font-weight: 500;
  margin-bottom: 5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 200px;
}

.upload-item-size {
  font-size: 0.8rem;
  opacity: 0.7;
}

.upload-item-progress-container {
  width: 100%;
  height: 4px;
  background-color: var(--upload-border);
  border-radius: 2px;
  overflow: hidden;
  margin-top: 5px;
}

.upload-item-progress {
  height: 100%;
  background-color: var(--upload-item-progress);
  border-radius: 2px;
  transition: width 0.3s ease;
}

.upload-item-actions {
  display: flex;
  align-items: center;
}

.upload-item-status {
  margin-right: 10px;
  font-size: 1rem;
}

.upload-item-remove {
  background: none;
  border: none;
  color: var(--upload-item-remove);
  cursor: pointer;
  font-size: 1rem;
  padding: 5px;
  transition: var(--upload-transition);
}

.upload-item-remove:hover {
  opacity: 0.8;
}
JavaScript
document.addEventListener('DOMContentLoaded', function() {
  const dropArea = document.getElementById('drop-area');
  const fileInput = document.getElementById('fileUpload');
  const previewArea = document.getElementById('previewArea');
  
  // Max file size in bytes (10MB)
  const MAX_FILE_SIZE = 10 * 1024 * 1024;
  
  // Allowed file types
  const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'video/mp4'];
  
  // Prevent default drag behaviors
  ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
    dropArea.addEventListener(eventName, preventDefaults, false);
    document.body.addEventListener(eventName, preventDefaults, false);
  });
  
  // Highlight drop area when item is dragged over it
  ['dragenter', 'dragover'].forEach(eventName => {
    dropArea.addEventListener(eventName, highlight, false);
  });
  
  ['dragleave', 'drop'].forEach(eventName => {
    dropArea.addEventListener(eventName, unhighlight, false);
  });
  
  // Handle dropped files
  dropArea.addEventListener('drop', handleDrop, false);
  
  // Handle files from input field
  fileInput.addEventListener('change', function() {
    handleFiles(this.files);
  });
  
  function preventDefaults(e) {
    e.preventDefault();
    e.stopPropagation();
  }
  
  function highlight() {
    dropArea.classList.add('active');
  }
  
  function unhighlight() {
    dropArea.classList.remove('active');
  }
  
  function handleDrop(e) {
    const dt = e.dataTransfer;
    const files = dt.files;
    
    handleFiles(files);
  }
  
  function handleFiles(files) {
    const filesArray = Array.from(files);
    
    if (filesArray.length === 0) return;
    
    // Process each file
    filesArray.forEach(file => {
      // Validate file type and size
      if (!validateFile(file)) return;
      
      // Create preview item
      const uploadItem = createUploadItem(file);
      previewArea.appendChild(uploadItem);
      
      // Simulate upload
      simulateUpload(uploadItem, file);
    });
    
    // Clear the input field to allow selecting the same file again
    fileInput.value = '';
  }
  
  function validateFile(file) {
    // Check file type
    if (!ALLOWED_TYPES.includes(file.type)) {
      alert(`File type not allowed: ${file.type}`);
      return false;
    }
    
    // Check file size
    if (file.size > MAX_FILE_SIZE) {
      alert(`File too large: ${file.name} (${formatFileSize(file.size)})`);
      return false;
    }
    
    return true;
  }
  
  function createUploadItem(file) {
    const item = document.createElement('div');
    item.className = 'upload-item';
    
    const iconClass = getFileIconClass(file.type);
    
    item.innerHTML = `
<div class="upload-item-icon">
  <i class="${iconClass}"></i>
</div>

<div class="upload-item-details">
  <div class="upload-item-name">${file.name}</div>
  <div class="upload-item-size">${formatFileSize(file.size)}</div>
  <div class="upload-item-progress-container">
    <div class="upload-item-progress" style="width: 0%"></div>
  </div>
</div>

<div class="upload-item-actions">
  <div class="upload-item-status">
    <i class="fas fa-spinner fa-spin"></i>
  </div>

  <button class="upload-item-remove">
    <i class="fas fa-times"></i>
  </button>
</div>
    `;
    
    // Add event listener to remove button
    item.querySelector('.upload-item-remove').addEventListener('click', function() {
      item.remove();
    });
    
    return item;
  }
  
  function simulateUpload(item, file) {
    const progressBar = item.querySelector('.upload-item-progress');
    const statusIcon = item.querySelector('.upload-item-status i');
    let progress = 0;
    
    // Simulate upload progress
    const interval = setInterval(() => {
      progress += Math.random() * 10;
      if (progress >= 100) {
        progress = 100;
        clearInterval(interval);
        
        // Update status icon
        statusIcon.className = 'fas fa-check';
        statusIcon.style.color = 'var(--upload-item-icon)';
      }
      
      progressBar.style.width = `${progress}%`;
    }, 200);
  }
  
  function getFileIconClass(fileType) {
    if (fileType.startsWith('image/')) {
      return 'fas fa-image';
    } else if (fileType === 'application/pdf') {
      return 'fas fa-file-pdf';
    } else if (fileType.includes('word')) {
      return 'fas fa-file-word';
    } else if (fileType.startsWith('video/')) {
      return 'fas fa-file-video';
    } else {
      return 'fas fa-file';
    }
  }
  
  function formatFileSize(bytes) {
    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
    if (bytes === 0) return '0 Byte';
    const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
    return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
  }
});