Forms

File input

The File Input component provides different types of file uploads based on user needs. It ensures a smooth and structured way to upload images, logos, and user profile pictures.

If you are using it with vue, you should import the following:

import { create, supported, registerPlugin, getOptions, OptionTypes } from 'filepond'
import FilePondPluginFileValidateSize from 'filepond-plugin-file-validate-size'
import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type'
import FilePondPluginImagePreview from 'filepond-plugin-image-preview'
import 'filepond/dist/filepond.min.css'
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css'

You can install them by

npm install vue-filepond filepond
npm i filepond-plugin-file-validate-size --save
npm i filepond-plugin-file-validate-type --save
npm i filepond-plugin-image-preview --save

General File Upload

The General File Upload component is designed for uploading various file types, including images, PDFs, and documents. It leverages the FilePond library for a smooth and intuitive upload experience.

View Mode
                          
HTML
<label class="form-label">صورة الغلاف</label> <input class="js-filepond" type="file">
<!-- Usage Example -->
<GeneralFileInput
  v-model="coverImage"
  label="صورة الغلاف"
  name="cover"
  :allow-multiple="false"
  accepted-file-types="image/*"
  required
/>

<!-- Vue Component Code Block -->
<script>
import { ref, onMounted, onUnmounted, defineProps, defineEmits } from 'vue'
import { create, supported, registerPlugin, getOptions, OptionTypes } from 'filepond'
import FilePondPluginFileValidateSize from 'filepond-plugin-file-validate-size'
import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type'
import FilePondPluginImagePreview from 'filepond-plugin-image-preview'

import 'filepond/dist/filepond.min.css'
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css'

registerPlugin(
  FilePondPluginFileValidateSize,
  FilePondPluginFileValidateType,
  FilePondPluginImagePreview,
)

const types = {
  boolean: Boolean,
  int: Number,
  number: Number,
  string: String,
  array: Array,
  object: Object,
  function: Function,
  serverapi: Object,
}

const optionTypes = OptionTypes
const filepondProps = {}
const eventNames = []
const defaultOptions = getOptions()

for (const key in optionTypes) {
  if (/^on/.test(key)) {
    eventNames.push(key.replace(/^on/, ''))
    continue
  }
  filepondProps[key] = {
    type: types[optionTypes[key]] || String,
    default: defaultOptions[key],
  }
}
</script>

<script setup>
const props = defineProps({
  label: String,
  placeholder: String,
  type: {
    type: String,
    default: 'text',
  },
  modelValue: Array,
  required: Boolean,
  className: String,
  name: String,
  id: String,
  ...filepondProps,
})

const emit = defineEmits(['update:modelValue', 'input', ...eventNames])
const pond = ref(null)
const inputElement = ref(null)

onMounted(() => {
  if (inputElement.value && supported) {
    const options = {
      ...props,
      labelIdle: ' اسحب أو <span class="filepond--label-action"> أختر ملفًا </span> لتحميل الصورة',
      // (All other Arabic labels...)
      credits: false,
    }

    pond.value = create(inputElement.value, options)

    for (const eventName of eventNames) {
      pond.value.on(eventName, (...args) => {
        const files = pond.value ? pond.value.getFiles() : []
        emit('input', files)
        emit('update:modelValue', files)
        emit(eventName, ...args)
      })
    }

    if (props.modelValue?.length) {
      pond.value.files = props.modelValue
    }
  }
})

onUnmounted(() => {
  if (pond.value) {
    for (const eventName of eventNames) {
      pond.value.off(eventName, (...args) => {
        emit(eventName, ...args)
      })
    }
    pond.value.destroy()
  }
})
</script>

<template>
  <div class="filepond--wrapper mb-3">
    <label v-if="label" class="form-label">{{ label }}</label>
    <input
      ref="inputElement"
      type="file"
      :id="id"
      :name="name"
      :class="className"
      :required="required"
      :placeholder="placeholder"
      :accept="acceptedFileTypes"
      :multiple="allowMultiple"
      :capture="captureMethod"
    />
  </div>
</template>
                    
HTML
<input type="file" class="filepond" name="filepond" multiple data-allow-reorder="true" data-max-file-size="3MB" data-max-files="3">

✅ Multiple File Uploads: Supports uploading multiple files simultaneously with multiple attribute.

✅ File Reordering: Drag & drop file reordering using data-allow-reorder="true".

✅ Ensure responsive layout adjustments for different screen sizes.

✅ Max Files: Define the maximum number of files that can be uploaded with data-max-files="3".

✅ Image Previews: Enable real-time previews of uploaded images.

✅ EXIF Orientation: Automatically correct image orientation based on EXIF metadata.

✅ Validation Plugins: Use additional plugins to validate file types, sizes, and other parameters.

Logo/Brand Image Upload

Used for uploading brand-specific images such as logos, favicons, and banners.

View Mode
                          
HTML
<label class="form-label">شعار المنصة <span class="text-danger">*</span></label> <label class="photo-uploader"> <input class="d-none" type="file"> <span class="photo-uploader__upload-area"> <span class="tticon-upload photo-uploader__icon"></span> <span class="photo-uploader__content"> <span class="photo-uploader__text">أعلى: <span class="text-english">300 KB</span></span> <span class="photo-uploader__text"><span class="text-english">300 KB</span></span> </span> </span> <span class="photo-uploader__preview" style="background-image: url('./images/photo-placeholder.svg')"></span> </label>
<!-- Usage Example -->
<BrandFileInput
  v-model="logoImage"
  label="صورة الشعار"
  name="logo"
  accepted-file-types="image/*"
  required
/>
<!-- Vue Component Code Block -->
<template>
  <label class="form-label">
    {{ label }}
    <span v-if="required" class="text-danger">*</span>
  </label>
 
  <label class="photo-uploader">
    <input
      ref="fileInputRef"
      class="d-none"
      type="file"
      :name="name"
      :accept="acceptedFileTypes"
      @change="handleFileChange"
      :required="required"
    />
    <span class="photo-uploader__upload-area" @click="fileInputRef.click()">
      <span class="tticon-upload photo-uploader__icon"></span>
      <span class="photo-uploader__content">
        <span class="photo-uploader__text">أعلى: <span class="text-english">300 KB</span></span>
        <span class="photo-uploader__text"><span class="text-english">300 KB</span></span>
      </span>
    </span>
    <span
      class="photo-uploader__preview"
      v-if="previewUrl"
      :style="{ backgroundImage: `url('${previewUrl}')` }"
    ></span>
  </label>
</template>
<script setup>
import { ref, computed, onBeforeUnmount } from 'vue'
 
const props = defineProps({
  modelValue: [File, String],
  label: String,
  name: String,
  acceptedFileTypes: String,
  required: Boolean,
})
 
const emit = defineEmits(['update:modelValue'])
 
const fileInputRef = ref(null)
 
// Holds a generated preview URL if modelValue is a File
const previewBlobUrl = ref('')
 
// Function to create and revoke object URL
function createAndRevokeObjectUrl(file) {
  if (previewBlobUrl.value) URL.revokeObjectURL(previewBlobUrl.value)
  return URL.createObjectURL(file)
}
 
// Computes the actual preview (whether it's a file blob or a string URL)
const previewUrl = computed(() => {
  if (props.modelValue instanceof File) {
    return createAndRevokeObjectUrl(props.modelValue)
  }
  return props.modelValue // treat as string URL
})
 
// Clean up when unmounting
onBeforeUnmount(() => {
  if (previewBlobUrl.value) URL.revokeObjectURL(previewBlobUrl.value)
})
 
function handleFileChange(event) {
  const file = event.target.files[0]
  if (!file) return
 
  emit('update:modelValue', file)
 
  // Reset file input to allow same file re-selection
  event.target.value = null
}
</script>

Profile Picture Upload

A specialized input field for uploading user avatars when creating or updating profiles.

View Mode
                          
HTML
<label class="upload-avatar-button mx-auto mb-3"> <input class="d-none" type="file"> <span class="tticon-camera"></span> </label>
<!-- Usage Example -->
<ProfilePictureFileInput
  v-model="profileImage"
  label="صورة الملف الشخصي"
  name="profile"
  accepted-file-types="image/*"
/>
<!-- Vue Component Code Block -->
<template>
  <label
    class="upload-avatar-button mx-auto mb-3"
    :style="{ backgroundImage: `url('${previewUrl}')` }"
    @click="fileInputRef.click()"
  >
    <input
      ref="fileInputRef"
      class="d-none"
      type="file"
      :name="name"
      :accept="acceptedFileTypes"
      @change="handleFileChange"
    />
    <span class="tticon-camera" :style="previewUrl ? { display: 'none' } : {}"></span>
  </label>
</template>
<script setup>
import { ref, computed, onBeforeUnmount } from 'vue'
 
const props = defineProps({
  modelValue: [File, String],
  name: String,
  acceptedFileTypes: String,
  required: Boolean,
})
 
const emit = defineEmits(['update:modelValue'])
 
const fileInputRef = ref(null)
 
// Holds a generated preview URL if modelValue is a File
const previewBlobUrl = ref('')
 
// Function to create and revoke object URL
function createAndRevokeObjectUrl(file) {
  if (previewBlobUrl.value) URL.revokeObjectURL(previewBlobUrl.value)
  return URL.createObjectURL(file)
}
 
// Computes the actual preview (whether it's a file blob or a string URL)
const previewUrl = computed(() => {
  if (props.modelValue instanceof File) {
    return createAndRevokeObjectUrl(props.modelValue)
  }
  return props.modelValue // treat as string URL
})
 
// Clean up when unmounting
onBeforeUnmount(() => {
  if (previewBlobUrl.value) URL.revokeObjectURL(previewBlobUrl.value)
})
 
function handleFileChange(event) {
  const file = event.target.files[0]
  if (!file) return
 
  emit('update:modelValue', file)
 
  // Reset file input to allow same file re-selection
  event.target.value = null
}
</script>
Last updated 3 months ago