The HTML file upload input is a single line of code,
<input type="file">, that lets visitors pick files from their device and attach them to a form. You control what it accepts, whether people can select more than one file, and how the browser shows the picker, all through a handful of attributes. There is no built-in file size limit in the HTML itself, so any size cap you want has to come from JavaScript or your server.
Content Table
The basic file upload input
At its core, a file upload input is just an input element with its type set to
file:
<label for="resume">Upload your resume</label>
<input type="file" id="resume" name="resume">
The browser renders this as a button plus a small text label showing the chosen file (or "No file chosen" when empty). The exact wording and button style come from the browser and operating system, not from your CSS, which is why the control looks different in Chrome, Firefox, and Safari.
The
name
attribute matters: it is the key your server reads to find the uploaded data. Skip it and the file never reaches the server, even if everything else is perfect.
Attributes that shape the input
Beyond
type
and
name, these are the attributes you will actually reach for:
| Attribute | What it does |
|---|---|
accept
|
Hints which file types the picker should show or prefer. |
multiple
|
Lets the user select more than one file at once. |
capture
|
On mobile, opens the camera or microphone directly instead of the file browser. |
required
|
Blocks form submission until at least one file is chosen. |
disabled
|
Greys out the control so it cannot be used or submitted. |
A file input cannot use
value
to pre-fill a file for security reasons, and it ignores attributes like
maxlength
or
pattern. If you are curious how
disabled
compares to read-only fields (spoiler: file inputs do not support read-only), the difference is explained in our guide on
readonly versus disabled inputs.
The accept attribute in detail
The
accept
attribute filters what the file picker suggests. You can pass file extensions, MIME types, or wildcards, separated by commas:
<!-- Only PDFs and Word docs -->
<input type="file" accept=".pdf,.doc,.docx">
<!-- Any image type -->
<input type="file" accept="image/*">
<!-- A specific MIME type -->
<input type="file" accept="image/png">
Wildcards like
audio/*
,
video/*
, and
image/*
are handy when you want a whole category. Mixing extensions and MIME types in the same attribute works fine, and browsers treat them case-insensitively. The
MDN reference on accept
lists the full behaviour across browsers.
Allowing multiple file upload
Add the
multiple
boolean attribute and users can select several files in one go (Ctrl or Cmd click, or shift-select in the dialog):
<input type="file" name="photos[]" accept="image/*" multiple>
A few things to know about multiple file upload:
-
The selected files land in the input's
filesproperty as aFileList, which you loop over in JavaScript. -
For PHP and similar backends, using array-style names like
photos[]lets the server receive them as an array. - Selecting new files replaces the previous selection; the input does not append. If you want an "add more" experience, you have to store files in JavaScript and manage the list yourself.
File size limits and where they live
Here is the part that trips people up: there is no
maxsize
attribute for a file upload input. HTML gives you zero control over the file size limit. Every real limit is enforced somewhere else:
| Where | How the limit is set |
|---|---|
| Client-side JavaScript |
Check
input.files[0].size
(in bytes) before submitting and warn the user early.
|
| Web server (Nginx/Apache) |
Directives like
client_max_body_size
reject oversized requests.
|
| Application runtime (PHP) |
upload_max_filesize
and
post_max_size
in php.ini.
|
Client-side checks improve the experience but are not security. Anyone can bypass JavaScript, so your server must always enforce the real cap. A quick client-side guard looks like this:
const input = document.querySelector('#resume');
input.addEventListener('change', () => {
const maxBytes = 5 * 1024 * 1024; // 5 MB
if (input.files[0] && input.files[0].size > maxBytes) {
alert('File is too large. Max 5 MB.');
input.value = '';
}
});
Browser behaviour and quirks
File inputs behave slightly differently everywhere, and knowing the quirks saves debugging time:
-
Styling is limited.
You cannot restyle the native button directly. The common trick is to hide the input with a visually-hidden class and trigger it by clicking a styled
<label>tied to it viafor. -
The displayed path is fake.
Browsers show
C:\fakepath\filename.jpginstead of the real path. This is a deliberate privacy feature and has been standard since the mid-2000s. -
Mobile turns capture into a shortcut.
On phones,
accept="image/*" capture="environment"can open the rear camera straight away, whilecapture="user"targets the front camera. -
Clearing a selection needs code.
There is no native "clear" button; set
input.value = ''in JavaScript to reset it.
Wiring it into a working form
A file input only sends its contents when the surrounding
<form>
uses the correct encoding. For file uploads you must set
enctype="multipart/form-data", otherwise the browser sends only the file name, not the file:
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="document" required>
<button type="submit">Send</button>
</form>
That
enctype
choice is the single most common reason uploads silently fail, so it is worth reading why in our deep dive on
HTML form enctype. The
action
attribute points to the endpoint that receives the file, and getting it right is covered in our explainer on
what the form action attribute actually does. If your form also collects longer text like cover letters or comments, a
textarea element
pairs naturally with the file field.
Collect file uploads without building a backend
Want an HTML file upload input that actually delivers submissions somewhere? Our contact form endpoint handles the multipart data and file attachments for you, so you can focus on the markup instead of server config.
Try our free form endpoint →
Frequently asked questions
No. There is no size attribute for file inputs in HTML. You enforce a file size limit with JavaScript by reading the file's size property before submission, and always again on your server or in your runtime config. Client-side checks only improve the user experience.
Not reliably. The accept attribute filters the file picker dialog to make choosing easier, but users can switch to "All files" and select anything. Treat it as a convenience hint, then validate the actual file type on the server before accepting it.
Add the multiple attribute to the input. Users can then shift or Ctrl click several files in the dialog. The selection arrives as a FileList you loop through in JavaScript, and using array-style names like files[] helps servers such as PHP receive them as an array.
The most common cause is a missing enctype. A form containing a file input must set enctype to multipart/form-data. Without it, the browser sends only the file name as text, not the file contents. Also confirm your input has a name attribute.
That fake path is a deliberate privacy protection built into browsers. Exposing the true local path could leak information about a user's system and folder structure. Your code should rely on the file's name and contents through the files property, never the displayed path string.