KQ-1265 · UPLOAD/ORBIT

Upload Orbit

An upload button over a real file input whose files orbit it while they go up: chosen or dropped files become dots that pop into a waiting line on the top edge on the snap spring, step out on the glide spring, and then sit round the button's perimeter at their progress, walked by arc length so one lap is the whole file, chasing each reported value on a critically damped spring while a softer spring drags a fading comet tail behind them. A finished dot completes its lap and hops into the count in the label, where the badge recoils on the recoil spring and the digit rolls on snap; a failed dot leaves along its tangent, falls and fades red while a red counter appears on the badge. Click, Enter or Space opens the system picker and files can be dropped anywhere on it; Escape cancels what is in flight, and after a batch with failures a press queues them again.

KQ-1265 · UPLOAD/ORBIT

Site photos

Fieldline · Inspection 14, Basin Road

Choose files, or drop them here.

no photos yet · drop or choose

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/upload-orbit

Props

onUpload
(file: File, progress: (share: number) => void, signal: AbortSignal) => Promise<unknown>
default —
Uploads one file: report progress from 0 to 1 as it goes and settle the promise when it is done or failed. Called for at most queue files at once; the signal aborts on Escape or unmount.
files
UploadOrbitFile[]
default —
Controlled list of files ({ id, name, size?, progress, status: "queued" | "uploading" | "done" | "error", error? }). The button reports every list it wants through onFilesChange and draws this one.
onFilesChange
(files: UploadOrbitFile[]) => void
default —
Every new list: files added, progress, completions, failures, retries.
onSelect
(files: File[]) => void
default —
The files the visitor chose or dropped that passed accept and maxSize.
accept
string
default —
What the picker offers and a drop accepts, as for a file input ("image/*,.pdf"). Refused files fall off at once and cannot be retried.
multiple
boolean
default true
Take several files at a time; off, only the first of a drop is taken.
maxSize
number
default —
The largest file accepted, in bytes. Larger ones fall off at once.
tail
number
default 0.6
How far each dot's comet tail trails it while it moves, 0 to 1, capped at 35% of the lap. 0 draws no tail.
speed
number
default 0.5
How quickly a dot runs to its reported progress, 0 to 1: a lazy glide that smooths a chunky connection, or a tight follow that dashes.
queue
number
default 2
How many files fly at once, 1 to 4; the rest wait in line as smaller dots.
label
string
default "Upload"
The text at rest.
pendingLabel
string
default "Uploading"
The text while files are queued, in flight or landing.
successLabel
string
default "Uploaded"
The text once a batch has landed.
errorLabel
string
default "Retry"
The text after a batch with failures that can be retried; a press queues them again.
state
"idle" | "pending" | "success" | "error"
default —
Controlled button state. Without it, the state follows the files: pending until the last finished dot has landed.
onStateChange
(state: "idle" | "pending" | "success" | "error") => void
default —
Each state the button moves to, from the change that caused it.
successHold
number
default 1600
How long Uploaded holds before the button rests, in ms.
errorHold
number
default 4000
How long Retry holds before the button rests, in ms.
size
"sm" | "md" | "lg"
default "md"
32, 40 or 48 px tall; the dots, their spacing and the orbit scale with it.
accent
string
default "var(--accent-bright)"
The orbit's colour: dots, tails and the lit track. Any CSS colour.
sound
boolean
default false
Play a pop for the drop or pick and a rising plip as each dot takes its place, only in answer to the visitor. Landings and failures are silent.
disabled
boolean
default false
Dims the button and refuses picks and drops.
className
string
default —
Merged onto the root's classes (the button and the 12 px frame its orbit stays inside).
ref
React.Ref<UploadOrbitHandle>
default —
An imperative handle: add(files) queues files as if dropped, open() opens the picker, cancel() stops everything in flight, retry() queues the failed files again.