KKiotaPay UI
Browse documentation

S3 File Uploader

A single-file uploader that talks to presigned storage. It validates, uploads with a progress bar, resolves a preview and handles deletion.

The demo above runs against a throwaway route that discards the bytes and serves a placeholder back, so you can see the real state machine without a bucket.

Installation

pnpm dlx shadcn@latest add https://kiotapay-ui-staging.staging.kiotapay.com/r/s3-file-uploader.json

Installs the component and lib/kiota-storage.tsx. Wire the adapter once — see Storage adapter.

Usage

'use client'

import * as React from 'react'

import { S3FileUploader } from '@/components/custom/s3-file-uploader'

export function ReceiptField({ form }) {
  const key = form.watch('receiptKey')

  return (
    <S3FileUploader
      fieldId="receipt"
      valueKey={key}
      filePath="/payout-receipts"
      onCompleteAction={(next) => form.setValue('receiptKey', next)}
      placeholder="Upload receipt"
      maxSize={5}
      acceptedFileTypes={['.png', '.jpg', '.pdf']}
    />
  )
}

Props

PropTypeDefaultDescription
fieldIdstring—Required. Id for the hidden file input; must be unique on the page.
valueKeystring | null—Current storage key. null shows the empty drop area.
filePathstring'/general-uploads'Destination prefix inside the bucket.
onCompleteAction(key: string | null, url?: string | null) => void—Fires with the new key, or null on removal.
maxSizenumber2Ceiling in megabytes.
acceptedFileTypesstring[]—Extensions ('.png') or MIME types ('image/png').
placeholderstring'Upload file'Drop-area caption.
uploadMode'direct' | 'proxy''direct'Transport. See Storage adapter.
readOnlybooleanfalseHides delete and blocks new selections.
error / setErrorstring / (error: string) => void—Lift the error into a parent form. Omit to let the component own it.
adapterStorageAdapter—Overrides the provider for this instance.

Behaviour notes

Uploading starts on selection. A separate upload button creates a state where the form looks complete but the bytes were never sent, and that failure stays invisible until submit.

A failed preview is not a failed upload. If the object stores but the preview URL cannot be resolved, onCompleteAction still fires with the key. The file is there; only the thumbnail is missing.

Removal always reports null. Whether the file was uploaded or only picked locally, onCompleteAction(null) runs so the bound form field clears with the UI.

Clearing valueKey from the parent resets the component, which is what makes it usable inside a form that resets after submit.

In-flight uploads are cancelled on unmount, on delete, and when a new file is chosen — the abort is wired to the request rather than left dangling.