Back to React Dropzone

Accepting specific file types

docs/pages/examples/accept.mdx

20.0.05.7 KB
Original Source

import {Accept, AcceptDuringDrag} from "../../components/examples";

Accepting specific file types

By providing the accept prop you can make the dropzone accept specific file types and reject the others. The value is an object keyed by MIME type with an array of file extensions as values.

Pairing a wildcard MIME type with extensions narrows it down to those extensions - {"image/*": [".jpeg", ".png"]} accepts only .jpeg and .png files, not every image type. Use an empty array ({"image/*": []}) to accept all files of that type.

<Accept />
tsx
function Accept() {
  const {acceptedFiles, fileRejections, getRootProps, getInputProps} = useDropzone({
    accept: {"image/jpeg": [], "image/png": []}
  });

  const acceptedFileItems = acceptedFiles.map(file => (
    <li key={file.path}>
      {file.path} - {file.size} bytes
    </li>
  ));

  const fileRejectionItems = fileRejections.map(({file, errors}) => (
    <li key={file.path}>
      {file.path} - {file.size} bytes
      <ul>
        {errors.map(e => (
          <li key={e.code}>{e.message}</li>
        ))}
      </ul>
    </li>
  ));

  return (
    <section className="container">
      <div {...getRootProps({className: "dropzone"})}>
        <input {...getInputProps()} />
        <p>Drag 'n' drop some files here, or click to select files</p>
        <em>(Only *.jpeg and *.png images will be accepted)</em>
      </div>
      <aside>
        <h4>Accepted files</h4>
        <ul>{acceptedFileItems}</ul>
        <h4>Rejected files</h4>
        <ul>{fileRejectionItems}</ul>
      </aside>
    </section>
  );
}

Grouping types for the file picker

When the File System Access picker is used (useFsAccessApi: true, in a secure context, on a supporting browser), showOpenFilePicker renders one filter row per group of types. To control that grouping and label each row, pass accept as an array of {description, accept} entries instead of a single map:

tsx
const {getRootProps, getInputProps} = useDropzone({
  useFsAccessApi: true,
  accept: [
    {description: "Images", accept: {"image/jpeg": [".jpg", ".jpeg"], "image/png": []}},
    {description: "Documents", accept: {"application/pdf": [".pdf"]}}
  ]
});

The picker then shows two rows - "Images" and "Documents" - rather than a single combined entry. description is optional; when omitted it is derived from the group's extensions (the plain object form, which can't express a description, is labeled this way too). Extension values may be a single string or an array (".pdf" and [".pdf"] are equivalent), matching showOpenFilePicker.

Grouping only affects the File System Access picker. On the native <input> fallback - the default, and where the browser doesn't support the FS Access API - all groups are flattened into one accept attribute and the descriptions are dropped. Accepted/rejected file validation is identical to listing the same types in the flat object form.

Reacting during the drag

Because of HTML5 File API limitations, file names/extensions aren't readable during a drag, so use MIME types (e.g. image/*) if you want to react with isDragAccept / isDragReject:

<AcceptDuringDrag />
tsx
const {isDragActive, isDragAccept, isDragReject, getRootProps, getInputProps} = useDropzone({
  accept: {"image/*": [".jpeg", ".png"]}
});

Mime type determination is not reliable across platforms. CSV files, for example, are reported as text/plain under macOS but as application/vnd.ms-excel under Windows.

isDragUnknown and custom validators

Your custom validator is typed (file: File) => … and usually reads file.name, file.size, etc. During a drag those aren't available (the browser only exposes a MIME type), so react-dropzone doesn't run the validator until drop. While a validator is configured and the built-in checks pass, the drag state is neither accept nor reject but isDragUnknown — the outcome can only be confirmed once the real files are dropped:

tsx
const {isDragAccept, isDragReject, isDragUnknown, getRootProps, getInputProps} = useDropzone({
  validator: myValidator
});

// isDragUnknown === true  → "these files might be rejected on drop"

A file whose MIME type is confidently wrong (or a selection that breaks multiple/maxFiles) is still isDragReject during the drag, even with a validator — a validator can only ever add rejections on drop, never rescue one.

Restoring the full MIME-type table

react-dropzone resolves each file's MIME type through file-selector's fromEvent — the default for the getFilesFromEvent prop — which infers the type from the file extension when the browser leaves a file typeless (common with drag 'n' drop and File System Access sources).

As of file-selector v4, only a small built-in set of common extensions is bundled, so the core stays lightweight. Because accept matches by file extension as well as MIME type, most configurations keep working regardless. You only need the full table when matching purely by MIME type (e.g. image/*) against typeless sources — pass the full COMMON_MIME_TYPES table via getFilesFromEvent (add file-selector to your dependencies to import from it):

bash
npm install file-selector
tsx
import {useDropzone} from "react-dropzone";
import {fromEvent} from "file-selector";
import {COMMON_MIME_TYPES} from "file-selector/mime";

function FullMimeCoverage() {
  const {getRootProps, getInputProps} = useDropzone({
    getFilesFromEvent: event => fromEvent(event, {mimeTypes: COMMON_MIME_TYPES})
  });
  // ...
}