Skip to content

Vue

The Vue client provides composables, components, and utilities for building file upload UIs in Vue 3 applications using the Composition API.

npm install @uploadista/vue
<script setup lang="ts">
import { useUpload } from "@uploadista/vue";
const { state, upload, abort, reset } = useUpload({
onProgress: (progress) => console.log(`Progress: ${progress}%`),
onSuccess: (result) => console.log("Complete:", result),
});
const handleFileSelect = (e: Event) => {
const target = e.target as HTMLInputElement;
const file = target.files?.[0];
if (file) upload(file);
};
</script>
<template>
<div>
<input type="file" @change="handleFileSelect" />
<div v-if="state.status === 'uploading'">
<progress :value="state.progress" max="100"></progress>
<span>{{ state.progress }}%</span>
<button @click="abort">Cancel</button>
</div>
<div v-if="state.status === 'success'">
Upload complete! File ID: {{ state.result?.id }}
</div>
</div>
</template>
import { createApp } from "vue";
import { createUploadistaPlugin } from "@uploadista/vue";
import App from "./App.vue";
const app = createApp(App);
app.use(createUploadistaPlugin({
baseUrl: "https://api.example.com",
storageId: "my-storage",
chunkSize: 1024 * 1024,
}));
app.mount("#app");

The Vue client supports two authentication modes that integrate with your existing auth system.

Use direct mode when you have your own authentication (JWT, API keys, sessions, OAuth):

app.use(createUploadistaPlugin({
baseUrl: "https://api.example.com",
storageId: "my-storage",
chunkSize: 1024 * 1024,
auth: {
mode: 'direct',
getCredentials: async () => ({
headers: {
'Authorization': `Bearer ${await getAccessToken()}`
}
})
}
}));

Common patterns for direct mode:

// With OAuth token
auth: {
mode: 'direct',
getCredentials: async () => ({
headers: { 'Authorization': `Bearer ${await oauth.getAccessToken()}` }
})
}
// With API key
auth: {
mode: 'direct',
getCredentials: () => ({
headers: { 'X-API-Key': import.meta.env.VITE_API_KEY }
})
}

Use UploadistaCloud mode for automatic JWT token exchange with your auth server:

app.use(createUploadistaPlugin({
storageId: "my-storage",
auth: {
mode: 'uploadista-cloud',
authServerUrl: '/api/auth/token',
clientId: import.meta.env.VITE_CLIENT_ID
}
}));
<script setup lang="ts">
const { state, upload, abort, reset, retry } = useUpload({
onProgress?: (progress) => void;
onComplete?: (result) => void;
onError?: (error) => void;
});
// state: { status, progress, bytesUploaded, totalBytes, error, result }
</script>
<script setup lang="ts">
const { uploads, stats, add, remove, clear, retryFailed } = useMultiUpload();
// stats: { totalFiles, completedFiles, failedFiles, totalProgress }
</script>
<script setup lang="ts">
const {
isDragging,
isOver,
files,
onDragEnter,
onDragLeave,
onDragOver,
onDrop,
clearFiles,
} = useDragDrop({
accept: ['image/*'],
maxSize: 10 * 1024 * 1024,
multiple: true,
onFilesDropped: (files) => {
// Handle dropped files
},
});
</script>
<template>
<div
@dragenter="onDragEnter"
@dragleave="onDragLeave"
@dragover="onDragOver"
@drop="onDrop"
:class="{ dragging: isDragging }"
>
Drop files here
</div>
</template>
<script setup lang="ts">
import { useMultiUpload, useDragDrop } from "@uploadista/vue";
const multiUpload = useMultiUpload();
const dragDrop = useDragDrop({
accept: ['image/*', 'application/pdf'],
maxSize: 50 * 1024 * 1024,
onFilesDropped: (files) => {
multiUpload.add(files);
},
});
</script>
<template>
<div
@dragenter="dragDrop.onDragEnter"
@dragleave="dragDrop.onDragLeave"
@dragover="dragDrop.onDragOver"
@drop="dragDrop.onDrop"
:class="{ dragging: dragDrop.isDragging }"
class="upload-zone"
>
<p v-if="!dragDrop.isDragging">
Drag files here or click to select
</p>
<p v-else>Drop files to upload</p>
<div v-if="multiUpload.uploads.length" class="upload-list">
<h3>Uploads ({{ multiUpload.uploads.length }})</h3>
<div v-for="upload in multiUpload.uploads" :key="upload.id" class="upload-item">
<div>{{ upload.filename }}</div>
<progress :value="upload.progress" max="100"></progress>
<span>{{ upload.progress }}%</span>
<button v-if="upload.status === 'uploading'" @click="multiUpload.remove(upload)">
Cancel
</button>
<button v-if="upload.status === 'error'" @click="multiUpload.retry(upload)">
Retry
</button>
</div>
</div>
<div class="stats">
Total: {{ multiUpload.stats.totalFiles }} |
Completed: {{ multiUpload.stats.completedFiles }} |
Failed: {{ multiUpload.stats.failedFiles }}
</div>
</div>
</template>
<style scoped>
.upload-zone {
border: 2px dashed gray;
padding: 2rem;
text-align: center;
}
.upload-zone.dragging {
border-color: blue;
background-color: #f0f8ff;
}
.upload-list {
margin-top: 2rem;
}
.upload-item {
margin-bottom: 1rem;
padding: 1rem;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>
<UploadZone
accept="image/*"
multiple
disabled
@file-select="handleFilesSelected"
>
<div class="custom-drop-zone">
<p>Drop files here</p>
</div>
</UploadZone>
<UploadList :uploads="uploads">
<template #item="{ upload }">
<div>
<span>{{ upload.filename }}</span>
<progress :value="upload.progress" max="100"></progress>
</div>
</template>
</UploadList>
import {
formatFileSize,
formatProgress,
isImageFile,
isVideoFile,
createFileSizeValidator,
createFileTypeValidator,
composeValidators,
} from "@uploadista/vue/utils";
formatFileSize(1024000); // "1 MB"
formatProgress(0.45); // "45%"
isImageFile(file); // true/false

Fully typed with TypeScript and Vue 3 types.