Skip to content

FileUpload Component

A versatile file upload component supporting single or multiple file uploads with drag-and-drop functionality, file preview integration, and configurable file type restrictions. Displays uploaded files with thumbnails, file information, and management controls.


Props

PropTypeDefaultDescription
modelValueFile | File[] | nullnullThe uploaded file(s) - supports v-model binding
acceptstring"*"Accepted file types (same format as HTML input accept)
multiplebooleanfalseEnable multiple file selection
maxFilesnumber-1Maximum number of files allowed (-1 for unlimited)
dragAndDropbooleantrueEnable drag and drop functionality
columnsnumber2Number of columns for file grid (multiple files mode)

Emits

EventParametersDescription
update:modelValueFile | File[] | nullEmitted when files are added or removed

Features

Single File Upload

  • Clean dropzone with click-to-upload interface
  • Shows file preview with thumbnail (for images) or icon (for other files)
  • Replace and remove buttons for easy file management
  • Displays file name and size information

Multiple File Upload

  • Grid layout with configurable columns
  • Add more files dynamically (until maxFiles limit)
  • Individual remove buttons for each file
  • Visual "Add File" tile when more files can be added

Drag and Drop

  • Visual feedback during drag operations
  • Ring highlight and background change on drag-over
  • Handles dropped files automatically
  • Can be disabled if not needed

Integrated File Preview

  • Click on any file to open the FilePreview component
  • Navigation between multiple files in preview mode
  • Supports images and PDFs with appropriate viewers

File Type Filtering

  • Configurable accept attribute for file type restrictions
  • Uses standard HTML input accept format
  • Examples: "image/*", ".pdf,.doc", "image/png,image/jpeg"

Usage Examples

Basic Single File Upload

vue
<script setup>
import { ref } from "vue";
import { FileUpload } from "dolphin-components";

const file = (ref < File) | (null > null);

const handleSubmit = () => {
  if (file.value) {
    console.log("Uploading:", file.value.name);
    // Submit file to server
  }
};
</script>

<template>
  <FileUpload v-model="file" accept="image/*" />

  <button @click="handleSubmit" :disabled="!file">Upload</button>
</template>

Multiple File Upload with Limit

vue
<script setup>
import { ref } from 'vue';
import { FileUpload } from 'dolphin-components';

const files = ref<File[]>([]);
</script>

<template>
  <FileUpload
    v-model="files"
    :multiple="true"
    :max-files="5"
    accept="image/*,.pdf"
  />

  <p class="text-sm text-gray-500">{{ files.length }} / 5 files selected</p>
</template>

Custom Grid Layout

vue
<script setup>
import { ref } from 'vue';
import { FileUpload } from 'dolphin-components';

const attachments = ref<File[]>([]);
</script>

<template>
  <FileUpload
    v-model="attachments"
    :multiple="true"
    :max-files="9"
    :columns="3"
    accept=".pdf,.doc,.docx,.xls,.xlsx"
  />
</template>

Without Drag and Drop

vue
<script setup>
import { ref } from "vue";
import { FileUpload } from "dolphin-components";

const document = (ref < File) | (null > null);
</script>

<template>
  <FileUpload v-model="document" :drag-and-drop="false" accept=".pdf" />
</template>

Form Integration

vue
<script setup>
import { ref, computed } from 'vue';
import { FileUpload } from 'dolphin-components';

const formData = ref({
  name: '',
  email: '',
  resume: null as File | null,
  documents: [] as File[]
});

const isFormValid = computed(() => {
  return formData.value.name &&
         formData.value.email &&
         formData.value.resume;
});

const submitForm = async () => {
  const data = new FormData();
  data.append('name', formData.value.name);
  data.append('email', formData.value.email);

  if (formData.value.resume) {
    data.append('resume', formData.value.resume);
  }

  formData.value.documents.forEach((file, index) => {
    data.append(`documents[${index}]`, file);
  });

  // Submit to server
  await fetch('/api/submit', { method: 'POST', body: data });
};
</script>

<template>
  <form @submit.prevent="submitForm">
    <div class="mb-4">
      <label>Name</label>
      <input v-model="formData.name" class="input-text" required />
    </div>

    <div class="mb-4">
      <label>Email</label>
      <input
        v-model="formData.email"
        type="email"
        class="input-text"
        required
      />
    </div>

    <div class="mb-4">
      <label>Resume (Required)</label>
      <FileUpload v-model="formData.resume" accept=".pdf,.doc,.docx" />
    </div>

    <div class="mb-4">
      <label>Additional Documents (Optional)</label>
      <FileUpload
        v-model="formData.documents"
        :multiple="true"
        :max-files="5"
        accept=".pdf,.doc,.docx"
      />
    </div>

    <button type="submit" class="btn btn-primary" :disabled="!isFormValid">
      Submit Application
    </button>
  </form>
</template>
vue
<script setup>
import { ref } from 'vue';
import { FileUpload } from 'dolphin-components';

const images = ref<File[]>([]);

const uploadToServer = async () => {
  for (const image of images.value) {
    const formData = new FormData();
    formData.append('image', image);

    await fetch('/api/gallery/upload', {
      method: 'POST',
      body: formData
    });
  }

  // Clear after upload
  images.value = [];
};
</script>

<template>
  <div class="space-y-4">
    <h3>Upload Gallery Images</h3>

    <FileUpload
      v-model="images"
      :multiple="true"
      :max-files="20"
      :columns="4"
      accept="image/*"
    />

    <div class="flex justify-end gap-2">
      <button
        @click="images = []"
        class="btn btn-outline-secondary"
        :disabled="!images.length"
      >
        Clear All
      </button>
      <button
        @click="uploadToServer"
        class="btn btn-primary"
        :disabled="!images.length"
      >
        Upload {{ images.length }} Image(s)
      </button>
    </div>
  </div>
</template>

Component States

Empty State (Single File)

  • Shows dashed border dropzone
  • Cloud upload icon with "Click to upload" text
  • Optional "or drag and drop" hint when drag-and-drop is enabled

File Selected State (Single File)

  • Shows file card with thumbnail/icon
  • Displays file name and formatted size
  • Replace button (swap icon) to change file
  • Remove button (X icon) to clear selection

Multiple Files State

  • Grid of file cards based on columns prop
  • Each card shows thumbnail, name, and size
  • Individual remove buttons per file
  • "Add File" tile when more files can be added

Drag Over State

  • Ring highlight around dropzone
  • Light primary color background
  • Visual feedback that drop is possible

File Card Features

Thumbnail Display

  • Images: Shows actual image thumbnail
  • Other Files: Shows document icon

File Information

  • Name: Truncated with ellipsis if too long
  • Size: Automatically formatted (B, KB, MB, GB)

Size Formatting

Size RangeFormat
0 bytes"0 B"
1 - 1023 bytes"X B"
1 KB - 1023 KB"X.X KB"
1 MB - 1023 MB"X.X MB"
1 GB+"X.X GB"

Accept Attribute Examples

Use CaseAccept Value
All imagesimage/*
Specific imagesimage/png,image/jpeg
PDF only.pdf or application/pdf
Documents.pdf,.doc,.docx,.xls,.xlsx
Media filesimage/*,video/*
Any file* (default)

TypeScript Support

typescript
import { FileUpload } from "dolphin-components";

// Single file
const singleFile = ref<File | null>(null);

// Multiple files
const multipleFiles = ref<File[]>([]);

Props Interface

typescript
interface FileUploadProps {
  modelValue: File | File[] | null;
  accept?: string;
  multiple?: boolean;
  maxFiles?: number;
  dragAndDrop?: boolean;
  columns?: number;
}

Best Practices

Usage Recommendations

  • Use appropriate accept values to filter file types early
  • Set reasonable maxFiles limits to prevent excessive uploads
  • Consider file size validation in your submission logic
  • Use the integrated preview feature for user experience

Performance Considerations

  • Large files are kept in memory - implement server-side chunked upload for very large files
  • Image thumbnails are generated via blob URLs
  • Consider implementing file size limits server-side as well

Accessibility

  • Keyboard accessible file input
  • Click anywhere on dropzone to trigger file dialog
  • Clear visual states for different interactions

Common Use Cases

  • Profile Picture Upload: Single image upload with preview
  • Document Attachments: Multiple document upload for forms
  • Image Galleries: Bulk image upload with grid preview
  • Resume/CV Upload: Single PDF upload with replace functionality
  • Product Images: E-commerce product image management
  • File Sharing: General-purpose file upload interface