File Upload - National Design System

Drag-and-drop file upload with built-in validation, progress tracking, and a full JavaScript API for custom upload workflows

File Upload

Two modes for collecting files: a drag-and-drop zone for prominent upload areas, or a compact browse button for inline forms

Drag and drop files here to upload
Maximum file size allowed is 2MB, supported file formats include .jpg, .png, and .pdf.

Built-in Features

Auto-initialization

Activates when .nds-file-upload is on the page. Dynamic elements added later are picked up automatically.

Drag and Drop

Files can be dragged onto the drop zone with visual feedback on hover. Toggled on and off with data-state="dropbox".

Client-side Validation

Validates file size, extension, and MIME type before upload. Rejected files appear in the list with an error message in Arabic or English.

Security

File names are sanitized to strip path traversal sequences, null bytes, and control characters before display and upload.

Upload Lifecycle

Five status stages (ready, uploading, processing, complete, error) with progress tracking, retry for failures, and abort for in-progress uploads.

Programmatic Control

Full JavaScript API to add, remove, upload, retry, and abort files. Intercept uploads via the cancelable beforeUpload event to set custom headers.

Bilingual Messages

Error and validation messages display in Arabic or English based on the page language setting.

Event-driven Integration

Nine custom events cover the full upload lifecycle, letting you hook into file selection, progress updates, success, and error handling.

Usage Guidelines

Best Practices

  • Use the drop zone mode (data-state="dropbox") for dedicated upload areas where file selection is the primary action on the page
  • Use the browse button mode (no dropbox state) when file upload is one field among many in a form
  • Use single file mode (data-state="single") for profile photos, document replacements, or anywhere only one file is expected
  • Always set data-max-file-size and data-allowed-types to give users immediate validation feedback rather than waiting for server rejection
  • Set data-max-files when the server has a file count limit. Excess files appear in the list with an error so users understand why they were rejected
  • Use the nds:upload:beforeUpload event to add authorization headers, CSRF tokens, or extra form fields. The component does not handle authentication.
  • Do not use this component for large file transfers (500MB+) that need chunked upload or resumable protocols. Build a custom solution with the events API as a starting point
  • Server-side validation must duplicate all client-side checks. Client validation improves UX but cannot be trusted for security
  • Combine data-allowed-types (extension) with data-allowed-mime-types for defense in depth: extensions can be spoofed, MIME types add a second check

Data Attributes

AttributeDescription
data-state="dropbox"Enables the drag-and-drop zone UI with dashed border and upload icon
data-state="single"Single file mode: new selection replaces the current file
data-upload-urlServer endpoint for XHR file uploads (POST)
data-auto-upload="true"Automatically upload files on selection instead of waiting for startUpload()
data-max-file-sizeMaximum file size in bytes. Default: 10485760 (10 MB)
data-max-filesMaximum number of files allowed. Default: unlimited
data-allowed-typesComma-separated file extensions: jpg,png,pdf
data-allowed-mime-typesComma-separated MIME types, supports wildcards: image/*,application/pdf

Events

EventDetail
nds:upload:ready{ instance }
nds:upload:selected{ files, allFiles, fileData }
nds:upload:validationError{ errors }
nds:upload:beforeUpload (cancelable){ fileData, formData, xhr }
nds:upload:progress{ fileData, progress }
nds:upload:success{ fileData, response }
nds:upload:error{ fileData, error, status }
nds:upload:removed{ fileData, fileId }
nds:upload:maxFilesReached{ maxFiles, currentCount }

JavaScript API

The NDS.Upload API provides static methods to access instances and instance methods to manage files, trigger uploads, and control the component state.

// ── Static methods ────────────────────────────────── NDS.Upload.init(); // Initialize all .nds-file-upload on page NDS.Upload.reinit(); // Re-scan DOM after dynamic changes NDS.Upload.create(element); // Manually create instance on element NDS.Upload.getInstance('.nds-file-upload'); // Get instance by selector or element NDS.Upload.whenReady('.nds-file-upload', fn); // Call fn(instance) when ready // ── File management ───────────────────────────────── const upload = NDS.Upload.getInstance('.nds-file-upload'); const fileId = upload.addFile(file, { // Add file to queue status: 'ready', // 'ready' | 'uploading' | 'processing' | 'complete' | 'error' progress: 0, // 0-100 error: null // Error message string }); // Returns fileId or null if max files reached upload.removeFile(fileId); // Remove file, abort if uploading upload.clearAllFiles(); // Remove all files, abort all uploads upload.getFile(fileId); // Returns { file, id, status, progress, error } upload.getAllFiles(); // Returns array of all file objects upload.getFilesByStatus('error'); // Filter by status // ── Upload control ────────────────────────────────── upload.startUpload(fileId); // Upload specific file upload.startUpload(); // Upload all 'ready' files upload.retry(fileId); // Reset error file and re-upload upload.abort(fileId); // Cancel in-progress upload // ── Status and progress ───────────────────────────── upload.setFileStatus(fileId, 'error', { error: 'Server rejected file' }); upload.setFileProgress(fileId, 75); // Auto-transitions to 'processing' at 100% // ── Component control ─────────────────────────────── upload.setDisabled(true); // Disable input, drag-and-drop, and buttons upload.refreshUI(); // Force full UI rebuild upload.getConfig(); // Returns frozen copy of current config upload.destroy(); // Remove listeners, abort uploads, clean DOM // ── Intercept uploads for custom headers ──────────── const el = document.querySelector('.nds-file-upload'); el.addEventListener('nds:upload:beforeUpload', (e) => { e.detail.xhr.setRequestHeader('Authorization', 'Bearer ' + token); e.detail.formData.append('folder', 'documents'); // e.preventDefault() cancels the upload });
Was this page useful?
60% of users said Yes from 2843 Feedbacks