File Upload
Two modes for collecting files: a drag-and-drop zone for prominent upload areas, or a compact browse button for inline forms
Built-in Features
Activates when .nds-file-upload is on the page. Dynamic elements added later are picked up automatically.
Files can be dragged onto the drop zone with visual feedback on hover. Toggled on and off with data-state="dropbox".
Validates file size, extension, and MIME type before upload. Rejected files appear in the list with an error message in Arabic or English.
File names are sanitized to strip path traversal sequences, null bytes, and control characters before display and upload.
Five status stages (ready, uploading, processing, complete, error) with progress tracking, retry for failures, and abort for in-progress uploads.
Full JavaScript API to add, remove, upload, retry, and abort files. Intercept uploads via the cancelable beforeUpload event to set custom headers.
Error and validation messages display in Arabic or English based on the page language setting.
Nine custom events cover the full upload lifecycle, letting you hook into file selection, progress updates, success, and error handling.
Sending Files to Your Server
The component owns the file picker, validation, and the on-screen list; your code decides where the files go. Two patterns cover almost every case, chosen by file size and whether you want per-file progress.
| Pattern | How it works | Best for |
|---|---|---|
| Bundle on submit | No data-upload-url. Files stay in the component until you read them on submit and POST them with the rest of the form to a single endpoint. | Forms and small attachments, atomic submit, simplest backend |
| Upload as you go | Set data-upload-url with data-auto-upload="true" (or a manual button calling startUpload()). Each file uploads on its own with a progress ring, then a success check or a retry. The submit then references the uploaded files. | Large files and media, when you want per-file progress and retry |
Three things to know with either pattern:
- Files never ride a native form submit. The component clears the native
<input>after selection, so always send them withgetAllFiles()ordata-upload-url. data-upload-urlreceives one file per request, not all of them at once, so the endpoint should accept a singlefilefield per POST.- On a failed upload, the file row shows the server's message when the response body is JSON with an
errorfield (e.g.{"error": "Quota exceeded"}), falling back to the HTTP status text, then a localized generic message. Override manually anytime withsetFileStatus(fileId, 'error', { error }). - The input's
acceptattribute only hints the OS picker and is advisory. Just setdata-allowed-types(which actually enforces extensions) and the component fillsacceptfrom it automatically, so you never hand-write the picker filter or risk it drifting from what is enforced.
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-sizeanddata-allowed-typesto give users immediate validation feedback rather than waiting for server rejection - Set
data-max-fileswhen 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:beforeUploadevent 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) withdata-allowed-mime-typesfor defense in depth: extensions can be spoofed, MIME types add a second check - Add
aria-live="polite"to the.nds-file-listso newly added rows and per-file validation errors are announced to screen-reader users. - The hidden
.nds-file-item-templateis optional: when omitted, the component renders rows from its built-in markup. Supply your own template only to customize the per-file row.
Data Attributes
| Attribute | Description |
|---|---|
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-url | Server endpoint for XHR file uploads (POST) |
data-auto-upload="true" | Automatically upload files on selection instead of waiting for startUpload() |
data-max-file-size | Maximum file size in bytes. Default: 10485760 (10 MB) |
data-max-files | Maximum number of files allowed. Default: unlimited |
data-allowed-types | Comma-separated file extensions: jpg,png,pdf |
data-allowed-mime-types | Comma-separated MIME types, supports wildcards: image/*,application/pdf |
Events
Every fileData payload is the consistent shape { file, id, status, progress, error }. For selected it is an array of these, and for validationError each errors[] entry carries one as its fileData.
| Event | Detail |
|---|---|
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?, response? }: status (HTTP status code) and response (raw response body) are present for HTTP errors only; network-level errors omit them |
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.