Skip to main content
FileUpload provides a complete file upload experience with drag-and-drop, file validation, progress tracking, and visual feedback for upload states.

Installation

npm install @soft-ui/react

Usage

import { FileUpload } from "@soft-ui/react/file-upload"

function Example() {
  return (
    <FileUpload
      label="Drag and drop or browse"
      hint="Supports PDF, DOC, and images up to 10MB"
      accept=".pdf,.doc,.docx,image/*"
    />
  )
}

API Reference

FileUpload

label
string
default:"'Drag and drop or browse'"
Label text shown in the dropzone
hint
string
Helper text shown below the label
accept
string
Accepted file types (e.g., "image/*,.pdf"). Supports:
  • MIME types: "image/png"
  • MIME wildcards: "image/*"
  • Extensions: ".pdf,.docx"
multiple
boolean
default:"true"
Allow multiple files to be selected
disabled
boolean
default:"false"
Whether the upload is disabled
files
FileUploadFile[]
Controlled files array. Each file has:
  • file: File object
  • state: "uploaded" | "uploading" | "error" | "warning"
  • progress: number (0-100)
onFilesChange
(files: FileUploadFile[]) => void
Callback when files change (for controlled mode)
onFilesAdded
(files: File[]) => void
Callback when new files are added
className
string
Additional CSS classes

FileItem

Individual file display with state indicators.
file
File
required
File object to display
state
'uploaded' | 'uploading' | 'error' | 'warning'
default:"'uploaded'"
Current state of the file:
  • uploaded: Green checkmark (success)
  • uploading: Animated spinner with progress bar
  • error: Red error icon
  • warning: Yellow warning icon
progress
number
default:"0"
Upload progress (0-100). Only shown when state="uploading"
displaySize
number
Override file size display (defaults to file.size)
onRemove
() => void
Callback when remove button is clicked
className
string
Additional CSS classes

Examples

Basic Upload

<FileUpload
  label="Upload documents"
  hint="PDF or Word documents only"
  accept=".pdf,.doc,.docx"
/>

Image Upload Only

<FileUpload
  label="Upload photos"
  hint="PNG, JPG, or GIF up to 5MB"
  accept="image/*"
/>

Single File Upload

<FileUpload
  label="Upload your resume"
  hint="PDF format only"
  accept=".pdf"
  multiple={false}
/>

Controlled with Upload Simulation

function ControlledUpload() {
  const [files, setFiles] = useState<FileUploadFile[]>([])

  const handleFilesAdded = (newFiles: File[]) => {
    // Start uploads
    const uploadFiles = newFiles.map((file) => ({
      file,
      state: "uploading" as const,
      progress: 0,
    }))
    setFiles([...files, ...uploadFiles])

    // Simulate upload progress
    uploadFiles.forEach((_, index) => {
      const interval = setInterval(() => {
        setFiles((current) => {
          const fileIndex = current.length - uploadFiles.length + index
          const updated = [...current]
          const currentProgress = updated[fileIndex].progress

          if (currentProgress >= 100) {
            updated[fileIndex] = {
              ...updated[fileIndex],
              state: "uploaded",
              progress: 100,
            }
            clearInterval(interval)
          } else {
            updated[fileIndex] = {
              ...updated[fileIndex],
              progress: currentProgress + 10,
            }
          }

          return updated
        })
      }, 200)
    })
  }

  return (
    <FileUpload
      files={files}
      onFilesChange={setFiles}
      onFilesAdded={handleFilesAdded}
    />
  )
}

Different File States

import { FileItem } from "@soft-ui/react/file-upload"

const demoFiles = [
  { file: new File([], "uploaded.pdf"), state: "uploaded", progress: 100 },
  { file: new File([], "uploading.pdf"), state: "uploading", progress: 45 },
  { file: new File([], "failed.pdf"), state: "error", progress: 0 },
  { file: new File([], "warning.pdf"), state: "warning", progress: 100 },
]

<div className="space-y-2">
  {demoFiles.map((fileData) => (
    <FileItem
      key={fileData.file.name}
      {...fileData}
      onRemove={() => console.log("Remove", fileData.file.name)}
    />
  ))}
</div>

Disabled State

<FileUpload
  label="Upload disabled"
  hint="This upload is currently disabled"
  disabled
/>

Build docs developers (and LLMs) love