Orbeez kit
Input

File upload

<FileUpload />
Files dropped anywhere on what it wraps, or picked with a trigger, shown as chips dyed by the kind of file, each saying how its upload is going.
or drop files anywhere here

Install

bash
npx shadcn@latest add https://orbeez-kit.vercel.app/r/file-upload.json

Usage

tsx
<FileUpload onFiles={(picked) => upload(picked)}>
  <Attachments wrap>
    {files.map((f) => (
      <Attachment
        key={f.id}
        name={f.name}
        bytes={f.bytes}
        status={f.status}       // 'uploading' | 'uploaded' | 'error'
        progress={f.progress}   // 0 to 1, while uploading
        error={f.error}         // said in place of the size
        onRetry={() => retry(f.id)}
        onRemove={() => remove(f.id)}
      />
    ))}
  </Attachments>
  <FileUploadTrigger>{(open) => <Button onClick={open}>Attach</Button>}</FileUploadTrigger>
</FileUpload>

Good to know

  • Moods. Dragging files over shows a bead with the love mood.
  • Key each Attachment by something that belongs to its file, never its index. Attachments then lets a removed chip step out at once while the rest slide over.
  • The drop sheet only comes up for files, not for text or links dragged over.
  • Start each upload as soon as the file is picked, and give its chip a status. Uploading, the icon becomes a bead filling its ring and the size line counts up; failed, the chip loses its colour, its edge breaks into dashes, a sad bead takes the place of the icon, and it says why and offers onRetry. Never red: every hue already belongs to some agent, so a red chip could pass for the work of one. Every state is the same size, so nothing round a chip moves as its upload goes.
  • Attachments is one row that scrolls sideways, with a fade at an edge there is more past, and a chip just added is scrolled into view; in a prompt, the box never grows however many files are on it. Pass wrap to let the chips break onto more lines, as in this drop zone.

Behaviour

  • Every chip is one fixed width and height, whatever its name and in every state, uploading, uploaded or failed: the icon box, the size line and the buttons change what they show, never the chip's size, so the chips after it never move.
  • Chips stay in one row that scrolls sideways, so the box round them never grows taller, unless wrap is set.
  • A chip just added is scrolled into view within the row. The page never scrolls.
  • When the box round the row grows or moves, the chips move with it in the same frame, never lagging or springing after it.
  • A removed chip leaves at once and the ones after it slide over into the gap.
  • Retry shows only on a failure worth retrying.
  • A failed chip wears no hue: neutral, with a dashed edge and a sad bead, so it can never be taken for an agent's colour.
  • A chip's tooltips show in full, even at the edge of a row that scrolls.