File Upload

Stable v1.0.2

A dropzone for uploading files with drag-and-drop, progress tracking, and previews. Cleans up its own memory so long-running pages don't leak Blob URLs.

Interactive Playground

Configure layout modes, limits, and validation rules in real-time. Drop a file to see the mapped progress bars.

Core UI Options
Dropzone (Standard)
Constraints & Validation
5 Files
10 MB
Component State
Queue Monitor
Internal Payload
0 / 5
Max: 5 Files

Click or drag files to upload

Drag and drop BLs, loading plans, or customs declarations.

image/* • .pdf • .csv

Awaiting platform upload events...
Live Source Code
<FileUpload
  v-model="files"
  id="cargo-manifest-upload"
  label="Upload Cargo Manifests"
  hint="Drag and drop BLs, loading plans, or customs declarations."
  accept="image/*, .pdf, .csv"
  multiple
  :max-files="5"
  :max-size="10485760"
  isShowProgressBar
  @change="handleUpload"
/>

Real-World Usage Examples

Explore implementation scenarios ranging from compact forms to custom DOM overriding.

1. Crew Passports (Button & Async Validator)

Utilizes layout="button" to save space. Bound to a custom async validator function mimicking a pre-flight resolution check for OCR.

<FileUpload
  v-model="passportFiles"
  layout="button"
  label="Select Passport Scan"
  accept="image/*"
  :multiple="false"
  :validator="validatePassport"
/>
Attach Vessel Logbook Browse

2. Vessel Logs (Compact Form)

The layout="compact" mode provides a slim, horizontal drag-and-drop zone perfect for dense forms and data tables.

<FileUpload
  v-model="compactFiles"
  layout="compact"
  label="Attach Vessel Logbook"
  accept=".pdf"
/>

Click or drag files to upload

Drag and drop files here or click to browse.

3. Custom Gallery Rendering (List Override)

Leveraging the #file-list slot to completely reconstruct the display of queued items into a masonry grid. The slot exposes the internal files array and the remove function.

<FileUpload v-model="customSlotFiles" label="Accounting Expense Receipts" multiple>
  <template #file-list="{ files, remove }">
    <div class="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3">
      <div
        v-for="item in files"
        :key="item.id"
        class="group relative flex flex-col rounded border border-main bg-surface p-3"
      >
        <button
          @click="remove(item.id)"
          class="absolute -top-2 -right-2 z-20 cursor-pointer rounded-full bg-danger p-1 text-on-danger opacity-0 shadow-md transition-opacity group-hover:opacity-100"
        >
          <Icon icon="lucide:x" class="h-3 w-3" />
        </button>
        <div class="mb-2 flex items-center gap-2 border-b border-main/50 pb-2">
          <Icon
            :icon="item.isImage ? 'lucide:image' : 'lucide:file-text'"
            class="h-4 w-4 shrink-0 text-muted"
          />
          <span class="flex-1 truncate text-xs font-bold text-main">{{ item.file.name }}</span>
        </div>
        <div class="flex items-center justify-between">
          <span class="font-mono text-[10px] text-muted uppercase"
            >{{ (item.file.size / 1024).toFixed(1) }} KB</span
          >
          <span
            v-if="item.status === 'error'"
            class="text-[10px] font-bold tracking-wider text-danger uppercase"
            >Rejected</span
          >
          <span v-else class="text-[10px] font-bold tracking-wider text-primary uppercase"
            >Pending</span
          >
        </div>
      </div>
    </div>
  </template>
</FileUpload>

Click or drag files to upload

Drag and drop files here or click to browse.

.pdf • .dwg • image/*

4. Custom Previews (Inversion of Control)

Uses the newly exposed #preview slot to inject custom thumbnails (like a lazy-loaded PDF.js canvas or specific SVG icons) based on the file extension, while keeping the standard list layout intact.

<FileUpload
  v-model="customPreviewFiles"
  label="Upload CAD Blueprints or Documentation"
  multiple
  accept=".pdf, .dwg, image/*"
>
  <template #preview="{ item }">
    <div
      v-if="item.extension === 'PDF'"
      class="flex h-full w-full items-center justify-center rounded-lg border border-danger/20 bg-danger/10"
    >
      <span class="text-[10px] font-black tracking-wider text-danger uppercase">PDF.js</span>
    </div>

    <div
      v-else-if="item.extension === 'DWG'"
      class="flex h-full w-full items-center justify-center rounded-lg border border-info/20 bg-info/10"
    >
      <Icon icon="lucide:drafting-compass" class="h-5 w-5 text-info" />
    </div>

    <Image
      v-else-if="item.isImage"
      :src="item.previewUrl"
      shape="rounded"
      class="h-full w-full object-cover shadow-sm"
    />
    <div
      v-else
      class="flex h-full w-full items-center justify-center rounded-lg border border-main/40 bg-surface text-muted"
    >
      <Icon icon="lucide:file" class="h-4 w-4 opacity-60" />
    </div>
  </template>
</FileUpload>

API Reference

Complete specifications for properties, complex object types, and exposed methods.

Props

Name
Type / Signature
Default
Description
v-model
File[]
[]
The array of validated raw File objects ready for form submission.
id
string
undefined
Overrides the auto-generated id applied to the hidden native file input and its label.
accept
string
""
Comma-separated string of allowed extensions or MIME types (e.g., "image/*, .pdf"). Evaluated manually to fix drag-and-drop bypass issues.
multiple
boolean
false
Allows selection of multiple files simultaneously.
maxSize
number
Infinity
Maximum allowed file size in bytes.
maxFiles
number
Infinity
Hard cap on the total number of files allowed in the queue.
disabled
boolean
false
Completely disables the dropzone and click triggers.
loading
boolean
false
Sets the UI into a processing state, disabling interactions and spinning the indicator.
isShowProgressBar
boolean
false
Renders a per-file progress bar in the queue, driven by the exposed updateProgressBar method as a file's status moves from pending to uploading to success.
error
string | boolean | string[]
false
Injects external validation error(s) (e.g. from a server response) alongside any internally generated file-validation errors.
layout
"dropzone" | "button" | "compact"
"dropzone"
Changes the core structural layout of the component.
label
string
"Upload Files"
Primary typography display above the component or inside the button.
hint
string
"Drag and drop files here..."
Secondary typography displayed inside the dropzone.
validator
(File) => boolean | string | Promise<...>
undefined
Inject custom synchronous or asynchronous deep validation logic. Return a string to display a specific error message.

Events

Event Name
Payload Signature
Description
@change
(files: File[])
Fired when new valid files are added or existing files are removed.
@error
(message: string, file?: File)
Dispatched when a file fails MIME type, size, or custom validation checks.
@remove
(file: File)
Fired when a user manually purges a file from the list.
@exceed-limit
()
Triggered when the user attempts to add more files than `maxFiles` allows.

Slots

Slot Name
Exposed Bindings
Description
trigger
{ trigger, isDragging, disabled }
Completely overrides the dropzone or button. Bind the exposed `trigger` method to your custom element.
file-list
{ files, remove }
Replaces the default file rendering list. `files` provides an array of internal `UploadFileItem` objects containing UI state (progress, previews).
preview
{ item }
Inversion of Control: Overrides just the thumbnail image/icon square, allowing you to inject heavy third-party renderers (like PDF.js) without bloating the core component.

Exposed Methods

Name
Type / Signature
Default
Description
triggerSelect
() => void
Programmatically opens the native OS file browser.
updateProgressBar
(id: string, progress: number, status?: UploadStatus)
Crucial for mapping backend Axios/Fetch upload progression directly to the file's internal UI state.