build69
build69  /  Components  /  Media & Files  /  Upload

Upload

v1.0.18Updated 19 Oct 2026

Upload component with four visual variants (default panel / compact / avatar / gallery), drag-drop, per-file progress, pause / resume / retry, and DnD reorder.

Preview

Live · 13 stories
DefaultOpen ↗
▸Why this is recommendedformuploadfiledropzone+4

The default, out-of-the-box Upload.

Recommended for+14
  • ✓Resumable multi-file uploads
  • ✓Image gallery uploads
  • ✓Document attachment pickers
  • ✓A one-file picker whose parent does its own PUT and must let the user pick again after the server refuses the file
Tags+6
formuploadfiledropzoneprogresspausereorderdefault
Features+4
  • Variants: default panel / compact / avatar / gallery
  • Spreads the remaining props onto the root element of every variant (data-* hooks, id, style, aria-*), with the built-in data-slot="upload" / data-variant hooks winning over a caller that tries to overwrite them
  • Drag-drop zone with hover affordance
  • Per-file progress bar
  • Pause / resume / retry per upload
  • DnD reorder of accepted files
  • Rejection feedback (size / type / count), dismissible so a refusal never stares back for ever
  • Recovery after a failed attempt: onFiles may return false (or reject) to mark those files failed; a failed entry frees its maxFiles slot; `ref` exposes reset() / remove(id) / fail(ids) / clearRejections() / openPicker()
  • replaceAtLimit — at the maxFiles limit a new pick replaces the oldest instead of being refused (default for maxFiles=1)
  • i18n: labels prop overrides every built-in string (status pills, rejection reasons, dropzone prompt/helper, aria-labels); percentages and byte sizes format through LocaleProvider (prettyBytes accepts an optional FormatLocale)
Not recommended for−2
  • ✕Single trivial file input (use Input type="file")
  • ✕File browser (use FileBrowser)

Install

Ask your agent, or call the MCP tool directly. The resolved bundle is written into your project.

get_registry_item({ name: "Upload" })

Usage

import { Upload } from '@/components/media/upload';

<Upload variant="gallery" accept={['image/*']} maxFiles={10} pausable reorderable onUpload={upload} />

Tick variants in the left menu — each adds a tab with that variant’s real story source, the same code the preview above renders.

Props

PropTypeRequired
variant

Visual layout

'default' | 'compact' | 'avatar' | 'gallery'—
onUpload

Upload handler returning a progress observable

function—
onFiles

The accepted files, handed over once they pass validation. Return or resolve false — or throw/reject — to tell the component your own transfer failed: those entries flip to failed, the error shows on the row with its remove button, and they stop occupying a maxFiles slot so the next pick is accepted. MCP feedback fb_96fd8fb9.

(files: File[]) => void | boolean | Promise<void | boolean>—
replaceAtLimit

At the maxFiles limit, let a new pick replace the oldest entries instead of being rejected. Defaults to true when maxFiles is 1 (a one-slot picker is a "choose a file" control); pass false for the strict refusal. MCP feedback fb_96fd8fb9.

boolean—
ref

Imperative handle: reset() empties the queue and the rejection banner, remove(id) drops one entry, fail(ids?, error?) marks entries failed with your own message, clearRejections() clears the banner, openPicker() opens the file dialog. This is how a parent that runs its own upload recovers the control after a refusal. MCP feedback fb_96fd8fb9.

React.Ref<UploadHandle>—
accept

Allowed MIME types or extensions

string[]—
maxFiles

Max total files

number—
maxSize

Max single-file size in bytes

number—
pausable

Allow pause / resume per file

boolean—
reorderable

Allow DnD reorder of files

boolean—
labels

Override any built-in UI string — status pills, rejection reasons, dropzone prompt ({browse} token), action aria-labels (i18n). Merged over DEFAULT_UPLOAD_LABELS; {token} templates for parameterized strings. Percentages and byte sizes follow LocaleProvider.

Partial<UploadLabels>—
...props

Every remaining standard div attribute is spread onto the root of whichever variant renders — data-* hooks, id, style, title, aria-describedby. The spread goes FIRST, so the built-in data-slot="upload" and data-variant hooks and the merged className can never be clobbered by a caller.

React.ComponentPropsWithoutRef<'div'>—

Related