CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-dropzone

Lightweight JavaScript library that transforms HTML elements into drag-and-drop file upload zones with thumbnail previews, progress tracking, and extensive customization options.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

event-system.mddocs/

Event System

Comprehensive event handling system with 25+ events covering the complete file upload lifecycle, inherited from the Emitter base class.

Capabilities

Event Management

Core event handling methods for registering, removing, and emitting events.

/**
 * Register an event listener
 * @param event - Event name to listen for
 * @param handler - Function to call when event occurs
 * @returns this (for method chaining)
 */
on(event: string, handler: Function): Dropzone;

/**
 * Remove event listeners
 * @param event - Event name (optional, removes all if not specified)
 * @param handler - Specific handler to remove (optional, removes all for event if not specified)
 * @returns this (for method chaining)
 */
off(event?: string, handler?: Function): Dropzone;

/**
 * Emit an event to all registered listeners
 * @param event - Event name to emit
 * @param args - Arguments to pass to event handlers
 * @returns this (for method chaining)
 */
emit(event: string, ...args: any[]): Dropzone;

// Aliases for compatibility
addEventListener(event: string, handler: Function): Dropzone;
removeListener(event?: string, handler?: Function): Dropzone;
removeAllListeners(event?: string, handler?: Function): Dropzone;
removeEventListener(event?: string, handler?: Function): Dropzone;

Usage Examples:

const dropzone = new Dropzone("#my-dropzone", { url: "/upload" });

// Register event listeners
dropzone.on("addedfile", function(file) {
  console.log("File added:", file.name);
});

// Chain multiple event listeners
dropzone
  .on("uploadprogress", (file, progress) => {
    console.log(`${file.name}: ${progress}%`);
  })
  .on("success", (file, response) => {
    console.log("Upload complete:", file.name);
  })
  .on("error", (file, message) => {
    console.error("Upload failed:", message);
  });

// Remove specific listener
const progressHandler = (file, progress) => console.log(progress);
dropzone.on("uploadprogress", progressHandler);
dropzone.off("uploadprogress", progressHandler);

// Remove all listeners for an event
dropzone.off("success");

// Remove all listeners for all events
dropzone.off();

Drag and Drop Events

Events triggered during drag and drop interactions.

/**
 * File(s) dropped on dropzone
 * @param event - Drop event
 */
on("drop", (event: DragEvent) => void): void;

/**
 * Drag operation started
 * @param event - Drag event
 */
on("dragstart", (event: DragEvent) => void): void;

/**
 * Drag operation ended
 * @param event - Drag event
 */
on("dragend", (event: DragEvent) => void): void;

/**
 * Dragged item entered dropzone
 * @param event - Drag event
 */
on("dragenter", (event: DragEvent) => void): void;

/**
 * Dragged item over dropzone
 * @param event - Drag event
 */
on("dragover", (event: DragEvent) => void): void;

/**
 * Dragged item left dropzone
 * @param event - Drag event
 */
on("dragleave", (event: DragEvent) => void): void;

Usage Examples:

const dropzone = new Dropzone("#my-dropzone", { url: "/upload" });

// Visual feedback during drag and drop
dropzone.on("dragenter", function(e) {
  this.element.classList.add("drag-over");
});

dropzone.on("dragleave", function(e) {
  this.element.classList.remove("drag-over");
});

dropzone.on("drop", function(e) {
  this.element.classList.remove("drag-over");
  console.log("Files dropped:", e.dataTransfer.files.length);
});

// Custom drag and drop handling
dropzone.on("dragover", function(e) {
  // Prevent default to allow drop
  e.preventDefault();
  e.dataTransfer.dropEffect = "copy";
});

File Lifecycle Events

Events that track files through their complete lifecycle from addition to completion.

/**
 * Single file added to dropzone
 * @param file - File that was added
 */
on("addedfile", (file: File) => void): void;

/**
 * Multiple files added at once
 * @param files - Array of files that were added
 */
on("addedfiles", (files: File[]) => void): void;

/**
 * File removed from dropzone
 * @param file - File that was removed
 */
on("removedfile", (file: File) => void): void;

/**
 * File processing started (status changed to uploading)
 * @param file - File being processed
 */
on("processing", (file: File) => void): void;

/**
 * Multiple files processing started
 * @param files - Array of files being processed
 */
on("processingmultiple", (files: File[]) => void): void;

/**
 * Upload completed successfully
 * @param file - File that completed
 * @param response - Server response
 */
on("success", (file: File, response: any) => void): void;

/**
 * Multiple uploads completed successfully
 * @param files - Array of files that completed
 * @param response - Server response
 */
on("successmultiple", (files: File[], response: any) => void): void;

/**
 * Upload failed or was canceled
 * @param file - File that failed
 * @param errorMessage - Error message
 * @param xhr - XMLHttpRequest object (if available)
 */
on("error", (file: File, errorMessage: string, xhr?: XMLHttpRequest) => void): void;

/**
 * Multiple uploads failed
 * @param files - Array of files that failed
 * @param errorMessage - Error message
 * @param xhr - XMLHttpRequest object (if available)
 */
on("errormultiple", (files: File[], errorMessage: string, xhr?: XMLHttpRequest) => void): void;

/**
 * Upload canceled by user or system
 * @param file - File that was canceled
 */
on("canceled", (file: File) => void): void;

/**
 * Multiple uploads canceled
 * @param files - Array of files that were canceled
 */
on("canceledmultiple", (files: File[]) => void): void;

/**
 * Upload completed (success or failure)
 * @param file - File that completed
 */
on("complete", (file: File) => void): void;

/**
 * Multiple uploads completed (success or failure)
 * @param files - Array of files that completed
 */
on("completemultiple", (files: File[]) => void): void;

Usage Examples:

const dropzone = new Dropzone("#my-dropzone", { url: "/upload" });

// Track file lifecycle
dropzone.on("addedfile", function(file) {
  console.log("Added:", file.name);
  
  // Create custom preview element
  const preview = document.createElement("div");
  preview.innerHTML = `<p>${file.name} (${file.size} bytes)</p>`;
  file.previewElement = preview;
  document.getElementById("file-list").appendChild(preview);
});

dropzone.on("processing", function(file) {
  console.log("Starting upload:", file.name);
  file.previewElement.classList.add("uploading");
});

dropzone.on("success", function(file, response) {
  console.log("Upload successful:", file.name, response);
  file.previewElement.classList.add("success");
  
  // Parse server response
  try {
    const data = JSON.parse(response);
    file.serverId = data.id;
    file.previewElement.innerHTML += `<p>Server ID: ${data.id}</p>`;
  } catch (e) {
    console.log("Non-JSON response:", response);
  }
});

dropzone.on("error", function(file, errorMessage, xhr) {
  console.error("Upload failed:", file.name, errorMessage);
  file.previewElement.classList.add("error");
  file.previewElement.innerHTML += `<p class="error">${errorMessage}</p>`;
  
  if (xhr) {
    console.error("HTTP Status:", xhr.status);
  }
});

dropzone.on("complete", function(file) {
  console.log("Finished processing:", file.name);
  file.previewElement.classList.remove("uploading");
  
  // Clean up after delay
  setTimeout(() => {
    if (file.status === "success") {
      file.previewElement.style.opacity = "0.5";
    }
  }, 2000);
});

Progress Events

Events for tracking upload progress at both individual file and total levels.

/**
 * Upload progress for individual file
 * @param file - File being uploaded
 * @param progress - Progress percentage (0-100)
 * @param bytesSent - Number of bytes sent so far
 */
on("uploadprogress", (file: File, progress: number, bytesSent: number) => void): void;

/**
 * Total upload progress across all files
 * @param totalProgress - Overall progress percentage (0-100)
 * @param totalBytes - Total bytes to upload across all files
 * @param totalBytesSent - Total bytes sent so far across all files
 */
on("totaluploadprogress", (totalProgress: number, totalBytes: number, totalBytesSent: number) => void): void;

Usage Examples:

const dropzone = new Dropzone("#my-dropzone", { url: "/upload" });

// Individual file progress
dropzone.on("uploadprogress", function(file, progress, bytesSent) {
  console.log(`${file.name}: ${Math.round(progress)}%`);
  
  // Update progress bar
  const progressBar = file.previewElement.querySelector(".progress");
  if (progressBar) {
    progressBar.style.width = progress + "%";
    progressBar.textContent = `${Math.round(progress)}%`;
  }
  
  // Update status text
  const statusEl = file.previewElement.querySelector(".status");
  if (statusEl) {
    statusEl.textContent = `${formatBytes(bytesSent)} / ${formatBytes(file.size)}`;
  }
});

// Total progress across all uploads
dropzone.on("totaluploadprogress", function(totalProgress, totalBytes, totalBytesSent) {
  console.log(`Overall: ${Math.round(totalProgress)}%`);
  
  // Update global progress indicator
  const globalProgress = document.getElementById("global-progress");
  if (globalProgress) {
    globalProgress.style.width = totalProgress + "%";
    globalProgress.textContent = `${Math.round(totalProgress)}% Complete`;
  }
  
  // Update stats
  document.getElementById("upload-stats").textContent = 
    `${formatBytes(totalBytesSent)} / ${formatBytes(totalBytes)}`;
});

function formatBytes(bytes) {
  if (bytes === 0) return '0 Bytes';
  const k = 1024;
  const sizes = ['Bytes', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

Upload Request Events

Events fired during the actual upload request process.

/**
 * Upload request about to be sent for single file
 * @param file - File being sent
 * @param xhr - XMLHttpRequest object
 * @param formData - FormData being sent
 */
on("sending", (file: File, xhr: XMLHttpRequest, formData: FormData) => void): void;

/**
 * Upload request about to be sent for multiple files
 * @param files - Array of files being sent
 * @param xhr - XMLHttpRequest object
 * @param formData - FormData being sent
 */
on("sendingmultiple", (files: File[], xhr: XMLHttpRequest, formData: FormData) => void): void;

Usage Examples:

const dropzone = new Dropzone("#my-dropzone", { url: "/upload" });

// Modify request before sending
dropzone.on("sending", function(file, xhr, formData) {
  // Add authentication header
  xhr.setRequestHeader("Authorization", "Bearer " + getAuthToken());
  
  // Add custom form data
  formData.append("userId", getCurrentUserId());
  formData.append("timestamp", Date.now());
  formData.append("fileCategory", file.type.split("/")[0]); // image, video, etc.
  
  // Add CSRF token
  formData.append("_token", getCsrfToken());
  
  console.log("Sending file:", file.name);
});

// Handle multiple file uploads
dropzone.on("sendingmultiple", function(files, xhr, formData) {
  console.log("Sending batch of", files.length, "files");
  
  // Add batch metadata
  formData.append("batchId", generateBatchId());
  formData.append("totalFiles", files.length);
  
  // Add individual file metadata
  files.forEach((file, index) => {
    formData.append(`file_${index}_originalName`, file.name);
    formData.append(`file_${index}_size`, file.size);
  });
});

// Track request details
dropzone.on("sending", function(file, xhr, formData) {
  // Log all form data entries
  for (let [key, value] of formData.entries()) {
    console.log("FormData:", key, value);
  }
  
  // Set up request timeout
  xhr.timeout = 60000; // 60 seconds
  
  xhr.addEventListener("timeout", function() {
    console.error("Upload timeout for:", file.name);
  });
});

System Events

Events for system-level states and limits.

/**
 * Dropzone reset (all files removed)
 */
on("reset", () => void): void;

/**
 * Maximum file limit exceeded
 * @param file - File that exceeded the limit
 */
on("maxfilesexceeded", (file: File) => void): void;

/**
 * Maximum file limit reached (but not exceeded)
 * @param files - Current files when limit was reached
 */
on("maxfilesreached", (files: File[]) => void): void;

/**
 * All files in queue have been processed
 */
on("queuecomplete", () => void): void;

/**
 * Thumbnail generated for file
 * @param file - File for which thumbnail was generated
 * @param dataUrl - Data URL of the thumbnail image
 */
on("thumbnail", (file: File, dataUrl: string) => void): void;

Usage Examples:

const dropzone = new Dropzone("#my-dropzone", {
  url: "/upload",
  maxFiles: 5
});

// Handle system events
dropzone.on("reset", function() {
  console.log("Dropzone reset - all files removed");
  document.getElementById("file-count").textContent = "0 files";
});

dropzone.on("maxfilesexceeded", function(file) {
  console.warn("Too many files! Cannot add:", file.name);
  alert(`Maximum ${this.options.maxFiles} files allowed`);
});

dropzone.on("maxfilesreached", function(files) {
  console.log("Maximum files reached:", files.length);
  document.getElementById("add-more").style.display = "none";
});

dropzone.on("queuecomplete", function() {
  console.log("All uploads finished!");
  
  // Show completion message
  const notification = document.createElement("div");
  notification.className = "notification success";
  notification.textContent = "All files uploaded successfully!";
  document.body.appendChild(notification);
  
  // Auto-hide after 3 seconds
  setTimeout(() => notification.remove(), 3000);
});

dropzone.on("thumbnail", function(file, dataUrl) {
  console.log("Thumbnail generated for:", file.name);
  
  // Use custom thumbnail display
  const img = document.createElement("img");
  img.src = dataUrl;
  img.className = "thumbnail";
  file.previewElement.appendChild(img);
});

Available Events List

Complete list of all events supported by Dropzone.js.

// All available events
const DROPZONE_EVENTS = [
  // Drag and drop events
  "drop", "dragstart", "dragend", "dragenter", "dragover", "dragleave",
  
  // File lifecycle events
  "addedfile", "addedfiles", "removedfile",
  "processing", "processingmultiple",
  "success", "successmultiple", 
  "error", "errormultiple",
  "canceled", "canceledmultiple",
  "complete", "completemultiple",
  
  // Progress events
  "uploadprogress", "totaluploadprogress",
  
  // Request events
  "sending", "sendingmultiple",
  
  // System events
  "reset", "maxfilesexceeded", "maxfilesreached", "queuecomplete",
  
  // Thumbnail event
  "thumbnail"
];

// Access the events array from instance
dropzone.events; // Returns array of all available event names

Usage Examples:

const dropzone = new Dropzone("#my-dropzone", { url: "/upload" });

// Register listeners for all events (for debugging)
dropzone.events.forEach(eventName => {
  dropzone.on(eventName, function(...args) {
    console.log(`Event: ${eventName}`, args);
  });
});

// Programmatically check available events
function listAvailableEvents(dropzoneInstance) {
  console.log("Available events:");
  dropzoneInstance.events.forEach(event => {
    console.log("-", event);
  });
}

listAvailableEvents(dropzone);

Install with Tessl CLI

npx tessl i tessl/npm-dropzone

docs

constructor-config.md

event-system.md

file-management.md

index.md

static-utilities.md

thumbnails.md

upload-processing.md

tile.json