albert.walickihire me
← all solutions
html

How to accept only certain file types in a file input?

Limit a file input with the accept attribute using MIME types or extensions, then validate the file in JavaScript and on the server.

Add the accept attribute to the file input. It takes a comma-separated list of MIME types, wildcards like image/*, or file extensions, and the file picker then shows only matching files.

<!-- any image -->
<input type="file" name="avatar" accept="image/*">

<!-- only PNG and JPEG -->
<input type="file" name="photo" accept="image/png, image/jpeg">

<!-- by extension -->
<input type="file" name="cv" accept=".pdf,.docx">

<!-- extensions and MIME types mixed -->
<input type="file" name="scan" accept=".pdf,image/*">

The values you can use:

  • image/*, audio/* or video/* for any file of that kind.
  • A full MIME type, such as application/pdf.
  • An extension starting with a dot, such as .pdf. Extensions are case-insensitive.

Spaces after the commas are fine.

accept is only a hint

accept filters what the picker shows, but it doesn't block anything. Many pickers let the user switch to "All files", and anyone can remove the attribute in dev tools or send a request without your form at all. So check the file in JavaScript for a better experience, and always check it again on the server.

const input = document.querySelector('input[name="cv"]');
const allowed = ['.pdf', '.docx'];

input.addEventListener('change', () => {
  const file = input.files[0];
  if (!file) return;

  const name = file.name.toLowerCase();
  const ok = allowed.some((ext) => name.endsWith(ext));

  input.setCustomValidity(ok ? '' : 'Choose a PDF or DOCX file.');
  input.reportValidity();
});

setCustomValidity() marks the input as invalid, so the form won't submit until the user picks another file. With multiple, loop over all of input.files.

You can check file.type instead of the name, but the browser mostly guesses the type from the extension, and it's an empty string when the type is unknown. Neither the name nor the type proves what's inside the file. The server has to check the contents.

Camera on phones

On phones, accept="image/*" lets the user choose between taking a photo and picking one from the library. The capture attribute asks the browser to open the camera directly:

<!-- back camera -->
<input type="file" accept="image/*" capture="environment">

<!-- front camera, for selfies -->
<input type="file" accept="image/*" capture="user">

Desktop browsers ignore capture. On mobile it skips the photo library, so only use it when a fresh photo is what you want, like scanning a receipt.

Formats without a reliable MIME type

Some formats don't get a consistent MIME type across systems. HEIC photos from iPhones may come with a type or with an empty one, and CSV files can show up as text/csv or something else, depending on the operating system and installed apps. List the extension together with the MIME type, so the picker shows the file either way:

<input type="file" accept="image/heic,image/heif,.heic,.heif">

To make the button look like the rest of your UI, see how to style a file input. To send the chosen file, see how to upload an image with a form.

more solutions
work with me

Got something that needs building?

Frontend builds, full-stack features in Django, design-system work. Available for work.

See my workGet in touch