Overview
useUploadKit
The useUploadKit composable is the heart of Nuxt Upload Kit. It provides a reactive, feature-rich API for managing file uploads.
Basic Usage
<script setup lang="ts">
const uploader = useUploadKit()
const handleFileSelect = async (event: Event) => {
const input = event.target as HTMLInputElement
if (input.files) {
await uploader.addFiles(Array.from(input.files))
}
}
uploader.onUpload(async (file, onProgress) => {
// Your upload logic here
const response = await fetch("/api/upload", {
method: "POST",
body: file.data,
})
return await response.json()
})
</script>
<template>
<input type="file" multiple @change="handleFileSelect" />
<button @click="uploader.upload()">Upload</button>
</template>
Return Value
The composable returns an object with the following properties and methods:
State
| Property | Type | Description |
|---|---|---|
files | Readonly<Ref<UploadFile[]>> | Reactive array of all files |
totalProgress | ComputedRef<number> | Overall upload progress (0-100) |
status | Ref<UploadStatus> | Current upload status ('waiting' or 'uploading') |
isReady | Readonly<Ref<boolean>> | true when initialization is complete |
Core Methods
addFile(file: File): Promise<UploadFile>
Add a single file. Runs validation and preprocessing automatically.
const file = await uploader.addFile(fileFromInput)
addFiles(files: File[]): Promise<UploadFile[]>
Add multiple files. Returns successfully added files (failed validations are filtered out).
const addedFiles = await uploader.addFiles(Array.from(input.files))
removeFile(fileId: string, options?): Promise<void>
Remove a file by ID. Optionally control whether to delete from remote storage.
Options:
| Option | Type | Default | Description |
|---|---|---|---|
deleteFromStorage | "always" | "never" | "local-only" | "always" | Controls storage deletion behavior |
deleteFromStorage values:
"always"- Always delete from storage if the file has aremoteUrl"never"- Never delete from storage, only remove from local state (useful for forms that reference shared files)"local-only"- Only delete files uploaded in this session (source === "local"), preserving files loaded viainitializeExistingFiles
// Default: removes from local state AND deletes from storage
await uploader.removeFile(file.id)
// Only remove from local state, keep in storage
await uploader.removeFile(file.id, { deleteFromStorage: "never" })
// Delete from storage only if this form uploaded it
await uploader.removeFile(file.id, { deleteFromStorage: "local-only" })
removeFiles(fileIds: string[]): UploadFile[]
Remove multiple files at once.
const removed = uploader.removeFiles(["file1", "file2"])
clearFiles(): UploadFile[]
Remove all files.
const allRemoved = uploader.clearFiles()
upload(): Promise<void>
Start uploading all files with status 'waiting'.
await uploader.upload()
reset(): void
Clear all files and reset state.
uploader.reset()
File Access Methods
getFile(fileId: string): UploadFile
Get a file by ID. Throws if not found.
const file = uploader.getFile("file-id")
getFileData(fileId: string): Promise<Blob>
Get the file's binary data. For remote files, fetches from the URL.
getFileURL() or getFileStream() instead.const blob = await uploader.getFileData(file.id)
getFileURL(fileId: string): Promise<string>
Get a URL for the file. For local files, creates an object URL. For remote files, returns the remote URL.
const url = await uploader.getFileURL(file.id)
// Use for <img src> or <video src>
getFileStream(fileId: string): Promise<ReadableStream<Uint8Array>>
Get a stream for processing large files without loading into memory.
const stream = await uploader.getFileStream(file.id)
const reader = stream.getReader()
while (true) {
const { done, value } = await reader.read()
if (done) break
processChunk(value)
}
File Manipulation
replaceFileData(fileId: string, newData: Blob, newName?: string, shouldAutoUpload?: boolean): Promise<UploadFile>
Replace a file's content (e.g., after cropping). Re-runs preprocessing to regenerate thumbnails.
// After user crops an image
const croppedBlob = await cropImage(originalBlob)
await uploader.replaceFileData(file.id, croppedBlob, "cropped-image.jpg")
updateFile(fileId: string, updates: Partial<UploadFile>): void
Update file properties directly.
uploader.updateFile(file.id, {
meta: { ...file.meta, customData: "value" },
})
reorderFile(oldIndex: number, newIndex: number): void
Move a file to a different position in the list.
uploader.reorderFile(0, 2) // Move first file to third position
Initialization
initializeExistingFiles(files: InitialFileInput[]): Promise<void>
Load existing files (e.g., from a database) into the uploader. Replaces the current file list.
// Load previously uploaded files
await uploader.initializeExistingFiles([{ storageKey: "uploads/file-1.jpg" }, { storageKey: "uploads/file-2.png" }])
appendExistingFiles(files: InitialFileInput[]): Promise<UploadFile[]>
Append pre-existing remote files without replacing current files. Returns the files that were actually added.
- Skips files already present (matched by
storageKey) - Respects
maxFileslimit - Emits
file:addedfor each appended file
// User picks files from a media library — inject them into the upload manager
const added = await uploader.appendExistingFiles([
{ storageKey: "library/photo-1.jpg" },
{ storageKey: "library/photo-2.jpg" },
])
console.log(`${added.length} files added`)
This is useful when files come from multiple sources (local picker, media library, external integrations) and you want all files managed as first-class citizens in a single files ref.
Plugins
addPlugin(plugin: Plugin): void
Add a plugin at runtime.
import { PluginImageCompressor } from "nuxt-upload-kit"
uploader.addPlugin(
PluginImageCompressor({
quality: 0.8,
}),
)
File Object
Each file in the files array has the following structure:
interface UploadFile {
id: string // Unique identifier
name: string // Original filename
size: number // Size in bytes
mimeType: string // MIME type
status: FileStatus // 'waiting' | 'preprocessing' | 'uploading' | 'complete' | 'error'
source: FileSource // 'local' | 'storage' | etc.
progress: {
percentage: number // 0-100
}
preview?: string // Thumbnail/preview URL
remoteUrl?: string // URL after upload
error?: FileError // Error details if failed
uploadResult?: any // Result from upload function
meta: Record<string, unknown> // Custom metadata
data: File | Blob | null // File data (null for remote files)
}
Complete Example
<script setup lang="ts">
import { PluginAzureDataLake } from "nuxt-upload-kit"
const uploader = useUploadKit({
storage: PluginAzureDataLake({
sasURL: "https://storage.blob.core.windows.net/container?sv=...",
path: "uploads",
}),
maxFiles: 10,
maxFileSize: 50 * 1024 * 1024,
allowedFileTypes: ["image/*"],
thumbnails: true,
imageCompression: { quality: 0.85 },
})
// Listen to events
uploader.on("file:added", (file) => {
console.log("File added:", file.name)
})
uploader.on("upload:complete", (files) => {
console.log("All uploads complete:", files.length, "files")
})
uploader.on("file:error", ({ file, error }) => {
console.error("Upload failed:", file.name, error.message)
})
const handleDrop = async (event: DragEvent) => {
event.preventDefault()
const files = Array.from(event.dataTransfer?.files || [])
await uploader.addFiles(files)
}
</script>
<template>
<div @drop="handleDrop" @dragover.prevent class="dropzone">
<p>Drop files here or</p>
<input type="file" multiple accept="image/*" @change="(e) => uploader.addFiles(Array.from(e.target.files))" />
</div>
<div class="file-list">
<div v-for="file in uploader.files" :key="file.id" class="file-item">
<img v-if="file.preview" :src="file.preview" class="thumbnail" />
<div class="file-info">
<span class="name">{{ file.name }}</span>
<span class="status">{{ file.status }}</span>
</div>
<progress v-if="file.status === 'uploading'" :value="file.progress.percentage" max="100" />
<button @click="uploader.removeFile(file.id)">Remove</button>
</div>
</div>
<div class="actions">
<span>Total progress: {{ uploader.totalProgress }}%</span>
<button @click="uploader.upload()">Upload All</button>
<button @click="uploader.clearFiles()">Clear All</button>
</div>
</template>

