Skip to content
Working With React

File uploads in React

Add file uploads to React forms with Qubeforms and FormData. Validate attachment size and count, handle multipart requests, and display upload and submission states.

1. Add attachments on a paid plan

Starter, Pro, and Business support files. Each file must be 1 byte to 5 MB (5,242,880 bytes), with 10 files maximum per submission across all fields. Start with A React form component, whose handler already sends FormData. No AWS credentials or read key belong in the upload form; it posts to the public endpoint.

2. Add an uncontrolled file input

Place this input inside the component’s fieldset and add encType="multipart/form-data" to its form element for native form submission. Do not bind a file input’s value to React state. attachments[] preserves multiple selected files. The example requires at least one file; accept guides the picker but does not enforce server policy.

<>
  <label>
    Attach files
    <input type="file" name="attachments[]" multiple required accept=".pdf,.jpg,.jpeg,.png" />
  </label>
  <p>Up to 10 PDF, JPEG, or PNG files. Maximum 5 MB each.</p>
</>

3. Check size and count before sending

Insert this check immediately after const body = new FormData(form); and before marking the request in flight. It gives early feedback while Qubeforms still validates the actual upload. For optional file inputs, explicitly omit empty selections from FormData rather than submitting an empty file. Do not convert the files to JSON or manually set the multipart Content-Type.

const files = [...body.values()].filter((value) => value instanceof File);
if (files.length > 10 || files.some((file) => file.size < 1 || file.size > 5 * 1024 * 1024)) {
  setFeedback('Choose up to 10 files, each between 1 byte and 5 MB.');
  return;
}

4. Show progress honestly

The React example displays a pending message until the server confirms receipt; it does not estimate an upload percentage. If your UI needs byte progress, use XMLHttpRequest upload events as demonstrated in Upload progress in Vue, adapting the reactive state to React. Sending 100 percent of the request does not mean that validation or storage succeeded. Keep the success message tied to the final HTTP and JSON response.

5. Preserve selections and retrieve files

Do not reset the form on errors; form.reset() in the success branch clears file inputs. Reloading or unmounting may require a visitor to select files again, and drafts do not store file bytes. Verified notification recipients receive temporary links. A trusted backend with the form’s read key can retrieve fresh uploads[].download_url values. See Adding file uploads for file restrictions, retention, and the different email and read-API link lifetimes.

6. Test uploads

Test one allowed file, multiple files, an empty file, more than 10 files, and a file over 5 MB. Check that the browser request is multipart and that the attachment reaches the submission. A successful JSON response confirms receipt, while notification and webhook delivery proceed asynchronously.

Keep private credentials private

Public form keys can appear in browser code. Read keys, management credentials, and webhook signing secrets must stay on the server.