Skip to content

React File Upload with Size and Type Limits

· by oks-ui team

A dashed dropzone with an upload arrow, and a file row below it part-way through uploading.
ShareXLinkedIn
On this page
  1. 1. A basic file field
  2. 2. Drag and drop
  3. 3. Limits that are enforced, not just written
  4. 4. The same rules inside a form
  5. 5. Showing upload progress
  6. 6. Check the limits on the server too
  7. A note on accessibility

File uploads look simple until you handle the real cases: someone drops a 40 MB video into an avatar picker, or picks a PDF where you wanted a photo. This tutorial builds an upload field that handles those politely.

import { FormFieldSet } from "oks-ui/form-field-set";
import "oks-ui/form-field-set.css";

1. A basic file field

The value is an array of the browser's own File objects:

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

<FormFieldSet
  type="file"
  name="attachment"
  label="Attachment"
  onChange={(v: unknown) => setFiles(v as File[])}
/>

2. Drag and drop

ui="dropzone" turns the field into a drop area, with your own wording:

<FormFieldSet
  type="file"
  name="attachment"
  label="Attachment"
  ui="dropzone"
  isDroppable
  dropLabel="Drop your file here"
  dropHelperText="or click to browse — PDF or PNG, up to 5 MB"
  browseLabel="Choose a file"
/>

Keep the click-to-browse path. Drag and drop is impossible on a phone and awkward with a keyboard.

Advertisement

3. Limits that are enforced, not just written

Three props do the work: accept for file types, maxFileSize in bytes, and maxFiles:

<FormFieldSet
  type="file"
  name="photos"
  label="Photos"
  multiple
  accept="image/png,image/jpeg"
  maxFileSize={5 * 1024 * 1024}
  maxFiles={4}
  preview="thumbnails"
  description="PNG or JPEG, up to 5 MB each, 4 files."
/>

A file that doesn't match is refused with a message, so the user finds out immediately instead of after a failed upload. preview="thumbnails" shows picked images as small tiles with a remove button.

Always write the limits in the description too. An error is a poor substitute for knowing the rule in advance.

4. The same rules inside a form

Inside an oks-ui Form, express the limits as validation rules so the form won't submit:

<FormFieldSet
  type="file"
  name="resume"
  label="Résumé"
  accept=".pdf"
  validation={{
    rules: { required: true, accept: ".pdf", maxFileSize: 2 * 1024 * 1024 },
    message: { maxFileSize: "That file is over 2 MB — try compressing it." },
  }}
/>

5. Showing upload progress

The field can show per-file progress while you upload. Give it a function that returns each file's state:

const [progress, setProgress] = useState<Record<string, number>>({});

<FormFieldSet
  type="file"
  name="photos"
  multiple
  onChange={(v: unknown) => upload(v as File[])}
  getFileUploadState={(file) => ({
    status: progress[file.name] === 100 ? "completed" : "uploading",
    progress: progress[file.name] ?? 0,
  })}
/>

Your upload function sends each file and updates progress; the field shows a bar per file and marks it complete.

6. Check the limits on the server too

Browser-side limits are a convenience, not a defence — anything can post to your endpoint. Repeat every check on the server: the file type (by content, not just the name), the size, and how many files. Store uploads outside your web root or in object storage, and give them names you generate rather than the ones you were sent.

A note on accessibility

The field is a real <input type="file"> behind the drop zone, so it works with the keyboard and screen readers, and the error message is announced when a file is refused. Test it by tabbing to the field and pressing Enter.

See every option on the file field page.

Advertisement

oks-ui team

We build oks-ui — a React component library in strict TypeScript, themed entirely through CSS custom properties, with no runtime dependencies beyond React. These posts are what we learned building it.

Read the docs · All posts

Was this post helpful?

ShareXLinkedIn