FileUpload

FileUpload is an uncontrolled dropzone for adding files through the browser picker or drag and drop. Choose accept, multiple and maxSizeMB around the server's real rules; the component's size feedback helps people recover, but it cannot replace server-side validation.

Examples

Accepted types and existing files

accept reaches the hidden file input and also contributes to the visible helper text. defaultItems seeds an existing uncontrolled list, useful when a form already has uploaded assets.

  • brand-guidelines.pdf825 KB

Single-file handoff

Set multiple={false} when the next step needs one file. onFiles receives browser File objects, while onChange reports the component's display items and simulated progress.

When to use

Use FileUpload when people must add one or more files and need drop, picker, validation and progress feedback in one place.

Reach for something else when:

  • The form only needs the browser's plain file field — use Input with type="file" when no dropzone or upload list is needed.
  • People are editing typed metadata, not adding a file — use Input or Textarea for the value itself.
  • Existing remote files need browsing and management — use a file manager view rather than an upload-only dropzone.

Accessibility

  • The drop zone is a native <button>, so it can receive focus and opens the hidden native file input on click.
  • Dragging changes visual state, while keyboard users retain the same browser file picker path through the button.
  • Each completed item includes .lyra-upload__check with role="img" and the accessible name “Upload complete” by default. Pass doneLabel to translate it; removeLabel receives each file name so remove-button names can follow local word order.
  • The visible label is button text, not a form <label>. Make its action and accepted file rules explicit through label, hint, accept and nearby instructions.

Props

NameTypeRequiredDescription
labelstringPrimary dropzone text.
hintstringHelper text, overriding the generated accept/size description.
acceptstringAccepted file types, forwarded to the hidden file input and shown in the helper text.
maxSizeMBnumberFiles larger than this many megabytes are added as error items.
multiplebooleanWhether more than one file can be added. Default `true`.
uploadDurationnumberSimulated upload duration in milliseconds. Default `1800`.
defaultItemsFileUploadItem[]Items used to seed the uncontrolled list.
onFiles(files: File[]) => voidCalled with the real browser `File` objects whenever files are added.
onChange(items: FileUploadItem[]) => voidCalled whenever the internal item list changes.
doneLabelstringAccessible name for the completed-upload icon. Default: `"Upload complete"`.
removeLabel(name: string) => stringAccessible name for each remove button. Receives the file name. Default: `` (name) => `Remove ${name}` ``.
classNamestringClass appended after the public `.lyra-upload` class.

Plain HTML

The React component handles the picker, drag events and progress. This markup shows the public classes used by the rendered upload state:

html
<div class="lyra-upload">
  <button class="lyra-upload__zone" type="button">
    <span class="lyra-upload__zone-icon" aria-hidden="true"></span>
    <span class="lyra-upload__zone-label">Drag files here or click to select</span>
    <span class="lyra-upload__zone-hint">.pdf,.png · Up to 5 MB per file</span>
    <input type="file" accept=".pdf,.png" multiple hidden tabindex="-1" />
  </button>
  <ul class="lyra-upload__list">
    <li class="lyra-upload__item">
      <span class="lyra-upload__item-icon" aria-hidden="true"></span>
      <span class="lyra-upload__item-body">
        <span class="lyra-upload__item-row">
          <span class="lyra-upload__item-name">brand-guidelines.pdf</span>
          <span class="lyra-upload__item-meta">825 KB</span>
        </span>
      </span>
      <span class="lyra-upload__check" role="img" aria-label="Upload complete"></span>
      <button
        class="lyra-upload__remove"
        type="button"
        aria-label="Remove brand-guidelines.pdf"
      ></button>
    </li>
  </ul>
</div>