Skip to content
EspañolEnglish
All components (204)

File upload

Management · FileUpload · .amset-upload

What it is and when to use it

A zone for dropping files, with its button to choose them: dragging does not work with the keyboard, so the button is not optional. Below, the list of what was chosen, with the size written like this ("980 kB", "2.4 MB") and a button to remove each one.

When to use it

  • Attaching invoices, receipts, the store's logo, a CSV to import.
  • acceptedTypes (MIME types, image/* or extensions such as .csv) and maxSizeMb filter what gets in; what is rejected arrives through onReject with its reason, and whoever uses it draws it (with an Alert, for example).
  • multiple to allow more than one (with maxCount as the limit); without it, choosing another replaces the previous one. directory chooses a whole folder.
  • The filter here is a convenience: the server has to check it again, because anyone can send a file without going through this screen.

When not to

  • Uploading them as soon as they are chosen, with a bar per file, retry and cancel: Uploader (Upload with progress), which mounts this zone with its list of uploads.
  • Showing attachments that are already uploaded (with download, progress or retry): FileList.

Keyboard: Tab reaches the zone, then the button ("Choose a file" or "Choose files"; Enter or Space open the system picker) and then each "Remove". Enter or Space on the zone also open the picker, and with focus on it files can be pasted from the clipboard.

Accessibility: the zone is named like the label, followed by its text ("Supplier invoices Drag the files here"). Each remove button says what it removes ("Remove factura-2026-0142.pdf") and removes only that file, even if there is another with the same name; the list is called "Files chosen for …" with the label after it. The browser only filters by type when choosing with the button; what arrives by dragging or pasting is checked by the component itself, and what cannot be read arrives through onReject ("The file could not be read").

Fine-tuning: CSS variables --amset-upload-*: -extra, -file-font, -file-padding, -font, -gap, -icon, -radius, -remove, -remove-icon, -target, -zone-padding, -zone-radius. The size moves the zone's padding, the icon and the font sizes. The remove cross is SEEN in -remove and PRESSED in -target.

What it looks like

Attach documents
Drag the files here

<FileUpload label="Attach documents" multiple onSelect={recibir} />

Props

Import it with import { FileUpload } from '@amset/ui'. Required props are marked.

PropTypeWhat it does
labelrequiredstringWhat is being uploaded. It is the name of the drop zone and of the list of chosen items.
onSelectrequired(files: readonly File[]) => void—
acceptedTypesreadonly string[]MIME types or extensions: `['application/pdf', '.csv']`.
classNamestringMerged with the library classes; it does not replace them.
directorybooleanChoose a whole FOLDER instead of separate files. Dropping a folder onto it does not traverse it.
disabledboolean—
errorstring—
filesreadonly File[]Files already chosen, so they can be rendered and removed.
hiddenLabelbooleanThe label for the screen reader only. The drop zone already carries its own name, so it can be hidden from view without losing anything.
hideListbooleanDo not draw the list of chosen files below: for whoever draws it on their own (`Uploader`).
hintstringHelp text: which formats and what size are accepted.
inputRefRef<HTMLInputElement>The real `<input type="file">` (it is hidden), to open the picker from your own button with `inputRef.current?.click()` (AMS-735).
maxCountnumberHow many files fit at most. The excess ones are rejected with their reason. Without this, no limit.
maxSizeMbnumberMaximum size per file, in megabytes.
multipleboolean—
onReject(rejected: readonly RejectedFile[]) => voidIt is called with those that did not pass the type or size filter, or could not be read.
size"sm" | "md" | "lg"—

It also accepts the attributes of the element it renders: className, style, data-*, aria-* and its events.

CSS variables

These CSS variables are how you adapt it. Declare them on the component's selector, not on :root: the stylesheet redeclares them in the rule itself, and a declaration on the same element always wins.

VariableDefault
--amset-upload-gapvar(--amset-space-2)
--amset-upload-zone-paddingvar(--amset-space-6) var(--amset-space-4)
--amset-upload-zone-radiusvar(--amset-radius-lg)
--amset-upload-icon1.75rem
--amset-upload-fontvar(--amset-text-base)
--amset-upload-file-paddingvar(--amset-space-2) var(--amset-space-3)
--amset-upload-file-fontvar(--amset-text-sm)
--amset-upload-radiusvar(--amset-radius)
--amset-upload-remove1.5rem
--amset-upload-remove-icon0.75rem
--amset-upload-targetvar(--amset-upload-remove)
--amset-upload-extracalc((var(--amset-upload-target) - var(--amset-upload-remove)) / 2)

How to change it

.amset-upload {
  --amset-upload-gap: ...;
  --amset-upload-zone-padding: ...;
}

In the test bench

Every state and variant, to try one at a time, on its page at ui.amset.tech: