
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
vue-multi-uploader
Advanced tools
[](https://www.npmjs.com/package/vue-multi-uploader) [](LICENSE)
A headless upload component that supports developers to custom for every project. DEMO
npm i vue-multi-uploader --save
# OR
yarn add vue-multi-uploader
Use bundler and Vue SFC:
<script setup lang="ts">
import { useMultiUploader } from 'vue-multi-uploader';
</script>
Include JS file.
<script src="path/to/package/dist/vue-multi-uploader.umd.cjs"></script>
<script>
VueMultiUploader.useMultiUploader();
</script>
ES Module
<script type="module">
import { useMultiUploader } from 'path/to/package/dist/vue-multi-uploader.js';
useMultiUploader();
</script>
This is a simple example of how to use the vue-multi-uploader component in a Vue 3 application.
The example demonstrates how to set up a file upload interface with drag-and-drop functionality,
progress indicators, and the ability to delete uploaded items.
Full example please refer to Demo.
<script setup lang="ts">
import {
type UploaderItem,
useMultiUploader,
} from 'vue-multi-uploader';
import { ref, useTemplateRef } from 'vue';
const dropzone = useTemplateRef('dropzone');
const items = ref < UploaderItem[] > ([]);
const {
openFileSelector,
deleteItem
} = useMultiUploader(items, '/api/upload', {
dropzone: dropzone,
maxFiles: 5,
onItemUploadSuccess(item, xhr) {
const res = JSON.parse(xhr.responseText);
item.url = res.url;
},
});
</script>
<template>
<div class="">
<!-- File List -->
<ul>
<li v-for="(item) of items" :key="item.key">
<!-- Item title -->
<div>
{{ item.title }}
</div>
<!-- Progress -->
<div class="progress progress-sm" style="height: 0.5rem">
<div class="progress-bar" :style="{ width: (item.progress * 100) + '%' }"></div>
</div>
<!-- Delete Button-->
<a href="#" @click.prevent="deleteItem(item)">
Delete
</a>
</li>
</ul>
<!-- Dropzone -->
<div ref="dropzone" class="dropzone"
style="height: 300px; cursor: pointer;"
@click="openFileSelector"
>
<div class="dropzone__content text-center">
<span class="fa-solid fa-upload" style="font-size: 2rem"></span>
<div>Click or drop to upload</div>
</div>
</div>
</div>
</template>
Every option item can be a value, Ref, computed, or function to make them reactive.
const disabledRef = ref(props.disabled);
useMultiUploader(items, '/api/upload', {
maxFiles: 5, // Value
maxConcurrent: () => 2, // Getter
disabled: disabledRef, // Ref
});
| Name | Type | Default | Description |
|---|---|---|---|
id | string | undefined | ID for the uploader instance, leave empty will auto generate. |
accept | string | undefined | Accepted file types for upload, separate by comma if multiple, can be mime type (image/*, text/plain) or ext name .jpg, .png. |
maxFiles | number | undefined | Maximum number of files allowed for upload. |
maxConcurrent | number | 2 | Maximum number of concurrent uploads. |
maxItemSize | number | undefined | Maximum size of a single file in bytes. |
disabled | boolean | false | Disables the uploader if set to true. |
readonly | boolean | false | Sets the uploader to read-only mode if set to true. |
dropzone | MaybeElement | undefined | Element or ElementRef to be used as the dropzone. |
onDragClass | string | h-ondrag | CSS class to apply when dragging files over the dropzone. |
autoStart | boolean | true | Automatically start uploading files when added, if set to false, you must call uploadStart() to start. |
prepareXhr | (xhr: XMLHttpRequest) => MaybePromise<XMLHttpRequest or void> | undefined | A function to configure the XMLHttpRequest object or return a new XMLHttpRequest object, can be async. |
onChange | (items: UploaderItem[]) => void | Triggered when the uploader items change. | |
onDeleteItem | (item: UploaderItem) => void | Triggered when an item is deleted from uploader. | |
onUploading | () => void | Triggered when uploading process starts. | |
onUploaded | () => void | Triggered when uploading process completes. | |
headers | Record<string, string> | Custom headers to be sent with the upload request. | |
data | Record<string, any> | Custom data to be sent with the upload request. | |
onItemUploadStart | (item: UploaderItem, xhr: XMLHttpRequest) => void | Triggered when an individual file upload starts. | |
onItemUploadSuccess | (item: UploaderItem, xhr: XMLHttpRequest) => void | Triggered when a file uploads successfully, you can get the API return url here and set to item. | |
onItemUploadFail | (item: UploaderItem, xhr: XMLHttpRequest) => void | Triggered when a file fails to upload. | |
onItemUploadEnd | (item: UploaderItem, xhr: XMLHttpRequest) => void | Triggered when an individual file upload finishes. | |
onItemUploadProgress | (item: UploaderItem, event: ProgressEvent) => void | Triggered during upload progress of a file. | |
onInvalidFile | (e: Error) => void | Triggered when a file with an invalid type or size is selected. |
Variables can be directly obtained by expanding the return values as follows:
const {
id,
accept,
maxFiles,
maxConcurrent,
disabled,
readonly,
items,
uploading,
progress,
addFiles,
removeItem,
clear,
startUpload,
eventBus,
headers,
data,
} = useMultiUploader(...)
| Name | Type | Description |
|---|---|---|
accept | Ref<string> | Accepted file types string (e.g., .jpg,.png) |
disabled | Ref<boolean> | Whether the uploader is disabled |
id | Ref<string> | Unique identifier for the uploader instance |
items | Ref<UploaderItem[]> | List of file items currently in the uploader |
maxConcurrent | Ref<number> | Maximum number of concurrent uploads |
maxFiles | Ref<number or undefined> | Maximum number of files allowed |
maxItemSize | Ref<number or undefined> | Maximum size of a single file in bytes |
readonly | Ref<boolean> | Whether the uploader is in read-only mode |
uploadUrl | Ref<string> | Target URL for uploads |
headers | Record<string, string> | Custom headers to be sent with the upload request. |
data | Record<string, any> | Custom data to be sent with the upload request. |
| Name | Type | Description |
|---|---|---|
acceptedTypes | Ref<string[]> | Array of accepted file types |
canUpload | Ref<boolean> | Whether uploading is allowed, if is readonly or disabled or reaches max files, this will be false |
eventBus | Emitter | Custom event bus for listening and triggering events |
isReadonly | Ref<boolean> | Whether the uploader is in read-only state, this will merge disabled and readonly |
isUploading | Ref<boolean> | Whether an upload is currently in progress |
totalSize | Ref<number> | Total size of all files in the uploader |
| Name | Type | Description |
|---|---|---|
addFile | (file: File) => UploaderItem | Add a file to the uploader |
addItem | (item: UploaderItem) => UploaderItem | Add an item to the uploader |
createItem | (file: File) => UploaderItem | Create a new item based on the file |
deleteItem | (child: UploaderItem) => void | Delete a specific file item from the uploader |
emits | (event: string, ...args: any[]) => void | Manually trigger specific events |
isImage | (filePath: string) => boolean | Determine if a file is an image based on its path |
isImageItem | (item: UploaderItem) => boolean | Determine if an item is an image based on UploaderItem |
on | (event: string, callback: (...event: any[]) => void) => () => void | Register event listeners and return a function to remove the listener |
openFileSelector | () => void | Open the file selection window |
uploadStart | () => Promise<PromiseSettledResult<UploaderItem>[]> | Start the upload process and return the result for each item |
stopItemUpload | (item: UploaderItem or XMLHttpRequest) => void | Stop the upload process for a specific item |
enqueueUploadFile | (item: UploaderItem) => Promise<UploaderItem> | Enqueue a file for upload, returns the created item or null if not added |
uploadFile | (item: UploaderItem) => Promise<UploaderItem> | Upload a single file, returns the uploaded item |
checkFile | (file: File) => void | Check if a file is valid, throw an Error if invalid |
Note you can modify some of the values in the return values, such as disabled, readonly, maxFiles etc.
The change will be reflected in the uploader instance.
If you have some exists files that you want to show in the uploader, you can prepare them in advance.
import { type UploaderItem, useMultiUploader } from 'vue-multi-uploader';
const defaultItems = ref<UploaderItem[]>([
{
key: '1',
title: 'File 1',
url: 'https://example.com/file1.jpg',
// The original database record data can be stored in the `data` prop.
data: {
id: 1,
title: 'File 1',
// ...
},
},
{
key: '2',
title: 'File 2',
url: 'https://example.com/file2.jpg',
// The original database record data can be stored in the `data` prop.
data: {
id: 1,
title: 'File 1',
// ...
},
},
]);
const { items, ... } = useMultiUploader(defaultItems, '/api/upload', {
...,
});
The UploaderItem interface is as follows:
export interface UploaderItem {
key: string;
url: string;
thumbUrl?: string;
title?: string;
file?: File;
data?: Record<string, any>;
uploadState: UploadState; // enum
progress: number;
xhr?: XMLHttpRequest;
error?: Error;
[props: string]: any;
}
You can set the uploaded URL to the item after the upload is complete. Use the onItemUploadSuccess callback to do
this.
const {
...
} = useMultiUploader(items, '/api/upload', {
onItemUploadSuccess(item, xhr) {
const res = JSON.parse(xhr.responseText);
item.url = res.url;
// If thumb image is smaller than the original image, you can set it to `thumbUrl`.
item.thumbUrl = res.thumb_url;
// If you want to store some returned data to the item, you can set it to `data` prop.
item.data = res.data;
},
});
You can add items programmatically by using the addFile or addItem method. If autoStart is set to true,
the upload will start automatically after adding the item.
const {
addFile,
addItem,
createItem,
} = useMultiUploader(items, '/api/upload', {
...
});
// Add a file
const item = addFile(file); // Return UploaderItem
// Add an item
const item = createItem(file);
addItem(item);
If autoStart is set to false, you need to call uploadStart().
const {
addFile,
uploadStart,
} = useMultiUploader(items, '/api/upload', {
autoStart: false,
...
});
const item = addFile(file);
uploadStart();
You can stop the upload process for a specific item by using the stopItemUpload method.
const {
stopItemUpload,
} = useMultiUploader(items, '/api/upload', {
...
});
function clickToStop(item: UploaderItem) {
stopItemUpload(item);
// Or stop by xhr
stopItemUpload(item.xhr);
}
If the file is invalid, you can handle it in the onInvalidFile callback.
const {
...
} = useMultiUploader(items, '/api/upload', {
onInvalidFile(e) {
if (e.name === 'InvalidFileType') {
console.error('Invalid file type:', e.message, e.file, e.accepted as string[]);
} else if (e.name === 'InvalidFileSize') {
console.error('Invalid file size:', e.message, e.file, e.maxSize);
}
},
});
If the upload fails, you can handle it in the onItemUploadFail callback.
const {
...
} = useMultiUploader(items, '/api/upload', {
onItemUploadFail(item, xhr) {
console.error('Upload failed:', item.error, xhr);
},
});
You can use the on method to listen to events.
const { on } = useMultiUploader(items, '/api/upload', {});
const off = on('item-upload-success', (item, xhr) => {
console.log('Item uploaded successfully:', item);
});
onUnmounted(() => {
// Remember release the event listener
off();
});
The eventBus is a dush() instance, so there are some features you can use:
const { eventBus } = useMultiUploader(items, '/api/upload', {});
eventBus.on('...', () => {...
});
eventBus.once('...', () => {...
});
The following events will match to on* callback in options:
| Event | Callback |
|---|---|
change | onChange |
delete-item | onDeleteItem |
uploading | onUploading |
uploaded | onUploaded |
create-item | onCreateItem |
item-upload-start | onItemUploadStart |
item-upload-success | onItemUploadSuccess |
item-upload-fail | onItemUploadFail |
item-upload-end | onItemUploadEnd |
item-upload-progress | onItemUploadProgress |
invalid-file | onInvalidFile |
There has a VueMultiUploader component that is a pre-built component for the uploader. Here is a simple example of how
to use it.
<script setup lang="ts">
import { MultiUploader, ItemCard, ItemCardPlaceholder } from 'vue-multi-uploader';
import { ref } from 'vue';
const items = ref([]);
const uploadUrl = '/api/upload';
const accept = '.jpg,.png';
function onItemUploadSuccess(item, xhr) {
console.log('Item uploaded successfully:', item);
}
function deleteItem(item) {
// Remove the item from the list
}
</script>
<template>
<MultiUploader
:items="items"
:upload-url="uploadUrl"
:max-files="5"
:max-concurrent="2"
:accept="accept"
@item-upload-success="onItemUploadSuccess"
>
<template #items="{items, instance: {canUpload, openFileSelector, deleteItem}}">
<div class="d-flex flex-wrap w-100 gap-3">
<ItemCard v-for="(item, index) of items"
:item
:i="index"
@delete="deleteItem"
/>
<ItemCardPlaceholder
v-if="canUpload"
class=""
text="Click or drop to upload"
@click="openFileSelector"
/>
</div>
</template>
</MultiUploader>
</template>
Examples please refer to Demo.
You can get the uploader instance from the component.
<script setup lang="ts">
import { MultiUploader } from 'vue-multi-uploader';
import { onMounted, useTemplateRef } from 'vue';
const uploader = useTemplateRef('uploader');
onMounted(() => {
const { items, uploadUrl, maxFiles } = uploader.value!.instance;
console.log(items, uploadUrl, maxFiles);
});
</script>
<template>
<MultiUploader ref="uploader" ...>
...
</MultiUploader>
</template>
FAQs
[](https://www.npmjs.com/package/vue-multi-uploader) [](LICENSE)
The npm package vue-multi-uploader receives a total of 1 weekly downloads. As such, vue-multi-uploader popularity was classified as not popular.
We found that vue-multi-uploader demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.