components

FileUpload

A dropzone plus file list. Previews are the real, unmodified file — no auto-dither or halftone — this system's stance that a file the user is about to upload should look like what it actually is.

tsx
<FileUpload label="Attachments" multiple />
label

Examples

Uncontrolled, with validation — accept/maxSize/maxFiles reject anything that doesn't fit, and onReject reports why:

tsx
<FileUpload
  label="Photos"
  accept="image/*"
  multiple
  maxFiles={5}
  maxSize={5 * 1024 * 1024}
  onReject={(rejections) => {
    for (const { file, reason } of rejections) {
      toast.show({ title: `${file.name} rejected: ${reason}` });
    }
  }}
/>

enableImageEditing routes each new image through ImageEditor first — one at a time, in a modal — before it joins the list. Cancelling the edit step keeps the file as-is rather than dropping it; a cancelled edit isn't the same as a cancelled upload:

tsx
<FileUpload
  label="Profile photo"
  accept="image/*"
  enableImageEditing
  imageEditorFeatures={{ crop: true, rotate: true, flip: false }}
/>

Controlled, for when the file list drives something else on the page:

tsx
const [files, setFiles] = useState<File[]>([]);

<FileUpload label="Attachments" value={files} onChange={setFiles} />;

Props

PropTypeDefaultDescription
accepttext—Passed straight through to the native file input's `accept`.
classNametext——
defaultValuereadonly——
descriptiontext——
disabledboolean——
enableImageEditingbooleanfalseOpens each new image in a crop/rotate/flip step (`ImageEditor`, in a `Dialog`) before it's added.
errortext——
imageEditorFeaturesreadonly—Passed through to the editing step's `ImageEditor`.
labeltext——
maxFilesnumber——
maxSizenumber—Bytes.
multiplebooleanfalse—
onChangereadonly——
onRejectreadonly—Files that didn't make it in — wrong type, too big, or over `maxFiles` — with why.
successtext——
valuereadonly——