Usage

Events

Listen to upload lifecycle events for full control over the upload process.

Events

Nuxt Upload Kit provides a comprehensive event system that lets you react to every stage of the upload lifecycle.

Listening to Events

Use the on method to subscribe to events:

const uploader = useUploadKit()

uploader.on("file:added", (file) => {
  console.log("File added:", file.name)
})

uploader.on("upload:complete", (files) => {
  console.log("Upload complete:", files.length, "files")
})

Core Events

File Events

file:added

Fired when a file is successfully added (after validation and preprocessing).

uploader.on("file:added", (file: UploadFile) => {
  console.log("Added:", file.name, file.preview)
})

file:removed

Fired when a file is removed.

uploader.on("file:removed", (file: UploadFile) => {
  console.log("Removed:", file.name)
})

file:replaced

Fired when a file's data is replaced (e.g., after editing/cropping).

uploader.on("file:replaced", (file: UploadFile) => {
  console.log("Replaced:", file.name, "New size:", file.size)
})

file:processing

Fired when a file enters the processing stage.

uploader.on("file:processing", (file: UploadFile) => {
  console.log("Processing:", file.name)
})

file:error

Fired when a file encounters an error during validation, processing, or upload.

uploader.on("file:error", ({ file, error }) => {
  console.error("Error with", file.name, ":", error.message)

  // Show user-friendly message
  toast.error(`Failed to upload ${file.name}: ${error.message}`)
})

Upload Events

upload:start

Fired when the upload process begins.

uploader.on("upload:start", (files: UploadFile[]) => {
  console.log("Starting upload of", files.length, "files")
  showLoadingIndicator()
})

upload:progress

Fired when an individual file's upload progress updates.

uploader.on("upload:progress", ({ file, progress }) => {
  console.log(file.name, "progress:", progress, "%")
})

upload:complete

Fired when the current upload batch completes (including any errors).

uploader.on("upload:complete", (files: UploadFile[]) => {
  console.log("Batch complete:", files.length, "files processed")
  hideLoadingIndicator()
})

files:uploaded

Fired when all files in the uploader reach complete status. This is the best event for final form submission.

uploader.on("files:uploaded", (files: UploadFile[]) => {
  console.log("All files uploaded successfully!")

  // Safe to submit form - all files are uploaded
  const urls = files.map((f) => f.remoteUrl)
  submitForm({ attachments: urls })
})
files:uploaded only fires once per "session" - adding new files resets it so it can fire again.

upload:error

Fired on upload errors.

uploader.on("upload:error", (error: FileError) => {
  console.error("Upload error:", error.message)
})

Reorder Events

files:reorder

Fired when files are reordered.

uploader.on("files:reorder", ({ oldIndex, newIndex }) => {
  console.log("File moved from", oldIndex, "to", newIndex)
})

Initialization Events

initialFiles:loaded

Fired when files specified in the initialFiles option have been loaded from storage.

uploader.on("initialFiles:loaded", (files: UploadFile[]) => {
  console.log("Loaded", files.length, "existing files")
})

initialFiles:error

Fired when loading initial files fails. Note that isReady will still be set to true to prevent the UI from being stuck in a loading state.

uploader.on("initialFiles:error", (error) => {
  console.error("Failed to load existing files:", error)
  toast.error("Could not load existing files")
})

Plugin Events

Plugins can emit their own events, automatically prefixed with the plugin ID.

Image Compressor Events

// Compression started
uploader.on("image-compressor:start", ({ file, originalSize }) => {
  console.log("Compressing", file.name, "from", originalSize, "bytes")
})

// Compression completed
uploader.on("image-compressor:complete", ({ file, originalSize, compressedSize, savedBytes }) => {
  console.log("Compressed", file.name)
  console.log("Saved", savedBytes, "bytes", `(${((savedBytes / originalSize) * 100).toFixed(1)}%)`)
})

// Compression skipped
uploader.on("image-compressor:skip", ({ file, reason }) => {
  console.log("Skipped compression for", file.name, ":", reason)
})

Listening to Any Event

You can listen to arbitrary event strings for plugin events:

// Listen to any string event
uploader.on("my-custom-plugin:custom-event", (data) => {
  console.log("Custom event:", data)
})

Event Types

// Core events (fully typed)
type UploaderEvents = {
  "file:added": UploadFile
  "file:removed": UploadFile
  "file:replaced": UploadFile
  "file:processing": UploadFile
  "file:error": { file: UploadFile; error: FileError }
  "upload:start": UploadFile[]
  "upload:complete": UploadFile[]
  "upload:error": FileError
  "upload:progress": { file: UploadFile; progress: number }
  "files:uploaded": UploadFile[] // All files complete
  "files:reorder": { oldIndex: number; newIndex: number }
  "initialFiles:loaded": UploadFile[]
  "initialFiles:error": unknown
}

Practical Examples

Progress Toast Notifications

const uploader = useUploadKit()

uploader.on("upload:start", (files) => {
  toast.info(`Uploading ${files.length} file(s)...`)
})

uploader.on("file:error", ({ file, error }) => {
  toast.error(`Failed: ${file.name} - ${error.message}`)
})

uploader.on("upload:complete", (files) => {
  toast.success(`Successfully uploaded ${files.length} file(s)`)
})

Analytics Tracking

uploader.on("upload:complete", (files) => {
  analytics.track("files_uploaded", {
    count: files.length,
    totalSize: files.reduce((sum, f) => sum + f.size, 0),
    types: [...new Set(files.map((f) => f.mimeType))],
  })
})

uploader.on("image-compressor:complete", ({ savedBytes }) => {
  analytics.track("bandwidth_saved", { bytes: savedBytes })
})

Form Integration

const formData = reactive({
  title: "",
  description: "",
  attachments: [] as string[],
})

uploader.on("upload:complete", (files) => {
  // Update form with uploaded file URLs
  formData.attachments = files.filter((f) => f.remoteUrl).map((f) => f.remoteUrl!)
})

uploader.on("file:removed", (file) => {
  // Remove from form data
  formData.attachments = formData.attachments.filter((url) => url !== file.remoteUrl)
})

Debug Logging

if (import.meta.dev) {
  const events = ["file:added", "file:removed", "file:error", "upload:start", "upload:progress", "upload:complete"]

  events.forEach((event) => {
    uploader.on(event, (data) => {
      console.log(`[Upload] ${event}:`, data)
    })
  })
}
Copyright © 2026