Uploading

Drop Upload can drive the actual file upload for you, not just the picking and previewing. Pass an uploadAdapter and the component takes care of the rest: per-file progress, error/retry, and (optionally) starting the upload automatically.

import { DropUpload, createSupabaseAdapter } from "../components/DropUpload"

const adapter = createSupabaseAdapter({
  url: "https://your-project.supabase.co",
  bucket: "uploads",
  getToken: () => yourSupabaseAnonKey,
})

<DropUpload uploadAdapter={adapter} />

Built-in adapters:

Every adapter implements the same small interface, so they're interchangeable:

interface UploadAdapter {
  upload(
    file: File,
    ctx: { onProgress: (percent: number) => void; signal?: AbortSignal },
  ): Promise<{ url?: string }>
}

Write your own adapter for any other provider by implementing this interface.

Automatic vs. manual upload

By default (autoUpload: true), a file starts uploading as soon as it passes validation. Set autoUpload={false} and each attached file waits with an upload button of its own in the list, so the user decides what goes up and when. The same trigger is available programmatically — get a ref to the component and call startUpload():

const ref = useRef<DropUploadHandle>(null)

<DropUpload ref={ref} autoUpload={false} uploadAdapter={adapter} />
<button onClick={() => ref.current?.startUpload()}>Upload</button>

startUpload(fileName) uploads a single file by name; call it with no arguments to upload every pending file. The same method is used internally for the "Retry" button shown on a failed upload.

Progress and status

Each attached file carries status ("idle" | "uploading" | "done" | "error") and uploadProgress (0-100). The list renders the whole run: a progress bar with its percentage while the file is going up, a green check once it lands, and a red frame with a "Retry" button if it fails. React to completion or failure with callbacks:

<DropUpload
  uploadAdapter={adapter}
  onUploadComplete={(file) => console.log("uploaded", file.name)}
  onUploadError={(file, error) => console.error("failed", file.name, error)}
/>

Without an uploadAdapter, Drop Upload behaves exactly as before — it only picks, validates, and previews files, and leaves the actual upload to you via onFilesChanged.