PDF extraction
How to Upload a File with HTML: A 2026 Developer's Guide
Learn how to upload file with html, from basic forms to modern JavaScript APIs. This 2026 guide covers drag-and-drop, progress bars, and server-side handling.
To upload a file with HTML, you need just two things inside a <form> tag: an <input type="file"> and the right encoding type. This simple combination creates the familiar "Choose File" button and tells the browser how to package the file for the server.
It's a pattern that has worked for decades. The form's enctype attribute must be set to "multipart/form-data". Without it, the browser sends only the filename, not the actual file content.
Table of Contents
- The Unbreakable HTML File Upload Pattern
- The Three Key Components
- Building Your First HTML Upload Form
- Crafting the Basic Form
- Guiding the User with Attributes
- Modernizing Your Uploads with JavaScript and Fetch
- The Asynchronous Upload Logic
- Handling the Core Drag-and-Drop Events
- From Upload to Live Link with OkraPDF
- A Practical API Example
- Frequently Asked Questions
- How Do I Limit the Upload File Size?
- Can I Show an Image Preview Before Uploading?
- What Is the Best Way to Show Upload Progress?
The Unbreakable HTML File Upload Pattern
Before you write any code, it’s worth understanding why this pattern is so reliable. A successful file upload depends on three specific pieces working together. If you miss one, the whole thing falls apart.

The Three Key Components
So, what are the three parts?
- The HTML
<form>: This is just the wrapper. It bundles up all the inputs you want to send. - The
<input type="file">: This is the magic piece. It tells the browser to open the native file selection dialog and gives you access to the chosen file. - The
enctype="multipart/form-data"attribute: This is the most common point of failure. This attribute on the<form>element tells the browser to build an HTTP request that can handle binary data (your file) mixed with regular text data (like other form fields).
This whole system dates back to RFC 1867, a proposal from 1995 that defined how browsers should handle form-based file uploads. It’s the bedrock for everything from simple profile picture uploads to the complex document pipelines you see in modern apps. You can discover more insights about file uploads on freecodecamp.org if you want to dig into the history.
This three-part structure—form, file input, and multipart encoding—is the universal, browser-agnostic method for sending files. Every server-side framework, from Node.js to Python, is built to parse this specific request format.
Once you have the file, you need a place to put it. For any serious application, that means integrating with a reliable cloud storage service, like setting up SaaS storage with Amazon S3. Getting this core upload mechanism right is the first and most critical step.
Building Your First HTML Upload Form
To upload a file with an HTML upload form, the simplest, most direct path is a standard web form. This is the bedrock method. It requires zero JavaScript and works in every browser, making it the most reliable way to get a file from a user's machine onto your server.
The whole thing hinges on a single HTML tag: <input type="file">. This tag tells the browser to show a "Choose File" button, which then opens the computer’s native file selection window. When a user picks a file, the browser gets a reference to it, ready for you to handle.

Crafting the Basic Form
Here’s a complete, minimal upload form you can copy and paste. Pay close attention to the <form> tag itself. The action attribute points to the server endpoint that will process the file, and method="post" is absolutely required for sending file data.
<form action="/upload" method="post" enctype="multipart/form-data"> <label for="file-upload">Select a PDF to upload:</label> <input type="file" id="file-upload" name="myFile" accept=".pdf" /> <button type="submit">Upload File</button> </form>
That name="myFile" attribute is crucial. It’s the key your server-side code will use to find and access the uploaded file within the request. If you forget it, the file data gets sent, but you won't be able to grab it on the other side.
The
enctype="multipart/form-data"attribute is non-negotiable. It instructs the browser how to package the request to handle binary file data alongside other form fields. If you leave it out, the browser will only send the filename, not the actual file content. This is a classic mistake.
Guiding the User with Attributes
You can make the user experience a lot smoother by adding a few helpful attributes to your file input. These aren't new ideas; the original RFC 1867, which first defined file uploads, described an ACCEPT attribute to suggest file types—a concept that survives today. You can read the full specification from the IETF to see just how old and established these ideas are.
A few attributes are especially useful for guiding the user. This table breaks down the essentials for your <input type="file"> element.
| Essential Attributes for Your File Input | ||
|---|---|---|
| Attribute | Purpose | Example |
name | The key your server uses to identify the file. Absolutely essential. | name="myFile" |
accept | Suggests which file types the user can select, filtering the file dialog. | accept=".pdf,.docx" |
multiple | A boolean attribute that lets the user select more than one file. | <input type="file" multiple> |
required | A boolean attribute ensuring the form cannot be submitted without a file. | <input type="file" required> |
Using accept and multiple gives the user helpful hints, but they don't replace server-side validation. A determined user can still bypass these client-side suggestions, so your server must always validate what it receives for security and data integrity.
Modernizing Your Uploads with JavaScript and Fetch
<iframe width="100%" style="aspect-ratio: 16 / 9;" src="https://www.youtube.com/embed/5Pd7twWZBzU" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
While the classic HTML form submission gets the job done, it comes with a full page reload. That feels jarring and clunky in a modern app. We can do better. By handling file uploads asynchronously with JavaScript, you can send a file to the server in the background without ever interrupting what the user is doing.
The two core tools for this job are the Fetch API and the FormData object. Think of FormData as a way to build a form in your code. You can programmatically add key-value pairs, including files, just as if a user had filled out a traditional form. It gives you complete control.
The Asynchronous Upload Logic
So how does it work? Instead of letting a <form> element handle the submission, we'll take over with JavaScript. You’ll grab the file from the input and send it off yourself.
The flow is pretty straightforward. First, you listen for the change event on your file input. Once the user selects a file, your script kicks in. You’ll access the chosen File object from the input's .files property.
Next, you create a new FormData object and append your file to it using formData.append('your-field-name', file). That field name is important—it has to be what your server-side code is expecting to receive.
Finally, you send it all off with a POST request using fetch(), passing your FormData object directly as the body. The browser is smart enough to handle the rest, automatically setting the correct Content-Type: multipart/form-data header for you.
This approach not only prevents the page from reloading but also lets you update your UI in real time. You can show a progress bar, then a success message, or handle an error from the server, all without a single page refresh. For instance, after a PDF is successfully uploaded, you could immediately kick off a process to pull data from it. For those kinds of tasks, tools like OkraPDF can be a huge help, especially when you need to convert PDF to structured JSON.
Using
FormDatawith theFetch APIis the standard for building responsive, non-blocking file uploads. It’s what users expect, and it gives you the power to create a much smoother experience than a full page refresh ever could.
If you're looking to get a broader view of the development landscape, Understanding front end tech for websites is a great resource to explore.
A standard "Choose File" button gets the job done, but let's be honest, a drag-and-drop zone just feels better. It's more intuitive for users and makes your application look polished and modern. Building one isn't about complex HTML, either. It’s all about orchestrating a few key JavaScript events.
The whole idea is to earmark a specific area on your page—usually just a <div>—as the drop target. You then use event listeners to take control of what happens when a user drags a file over that spot. If you skip this, the browser will fall back to its default behavior, which is to open the dropped file directly. That's definitely not what we want.
Handling the Core Drag-and-Drop Events
To make an effective drop zone, you really only need to handle three primary events. For each one, you’ll have to prevent the browser's default action so your own custom logic can run instead.
Here are the essential event listeners to attach to your drop zone element:
dragover: This event fires constantly as a file is dragged over the element. You must callevent.preventDefault()here. This is your way of telling the browser, "Yes, this is a valid place to drop a file." It's also the perfect moment to add a visual cue, like a glowing border, to let the user know the area is active.dragleave: This fires the moment the dragged file leaves your designated area. Use this event to clean up and remove any visual feedback, returning the zone to its original state. Simple.drop: This is the main event. It fires when the user lets go of the file over your zone. You'll callevent.preventDefault()again to stop the browser from trying to open the file itself.
Heads up: You absolutely must call
event.preventDefault()on both thedragoveranddropevents. If you forget to do it ondragover, thedropevent will never even fire. The browser won't see your element as a valid target, and nothing will happen when the user releases the file. It’s a classic mistake.
Inside your drop event handler, you can get the files from event.dataTransfer.files. This gives you a FileList object, which is easy to loop over.
From here, the process is exactly the same as handling files from a standard input. You can create a FormData object, append each file, and send it to your server using the Fetch API. This approach lets you build a slick, modern UX while plugging it into the same reliable upload logic we’ve already covered.
From Upload to Live Link with OkraPDF
Theory is one thing, but let's put this into practice. A common job for any developer is to take a user's file upload and immediately turn it into a shareable link. With OkraPDF, you can build this exact "Cloudinary-for-PDFs" flow without having to provision your own servers, S3 buckets, or CDNs.
It's a straightforward process: the user provides a file, you POST it to an API, and you get a permanent URL back.

The key is to manage the browser's native drag events and then use the Fetch API to handle the actual upload in the background, which is what the graphic above breaks down.
A Practical API Example
The OkraPDF /host endpoint gives you free PDF hosting. You can POST a file directly to it and get a permanent, CDN-served link in the response.
Here’s a concrete JavaScript fetch example showing exactly how that works.
async function uploadAndHostPDF(file) {
const formData = new FormData();
formData.append('file', file);
try {
const response = await fetch('https://api.okrapdf.com/v1/host', {
method: 'POST',
body: formData,
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('File hosted successfully!');
console.log('Shareable Link:', data.url);
// You can now use this link in your application
return data.url;
} catch (error) {
console.error('Upload failed:', error);
}
}
The response JSON gives you a url for the hosted file, which you can use immediately in your app. Our guide on how to get a PDF to link offers a few more tips on what to do with your new URL.
When you offload file hosting to a specialized API, you get to skip the entire headache of managing infrastructure. This lets you focus on building features for your users, not managing file servers and storage policies.
Once your PDF is live, you'll need to know how to make it accessible by linking to it from your website or app. For a good walkthrough on that, check out this guide from CatchDiff on robust PDF linking.
Frequently Asked Questions
Once you start building file uploads, the same few questions pop up every time. Here are some quick, practical answers for the issues developers hit most when they upload a file with HTML.
How Do I Limit the Upload File Size?
You need to attack this on two fronts. First, on the client side, you can check the file.size property in JavaScript before the upload even starts. This gives the user instant feedback without wasting their bandwidth on a file that's just going to be rejected.
But you can't trust the client. Those checks can be bypassed. You must also enforce the limit on your server. If you're using Node.js, a library like Multer makes this easy; you just set a fileSize limit in the configuration, and it will automatically reject any oversized files.
Can I Show an Image Preview Before Uploading?
Yes, and you absolutely should. After a user selects an image, you can use the FileReader API that's built into every modern browser. Just call readAsDataURL(file) on the selected image file.
The browser will generate a Base64-encoded string representing the image data. You can plug this string directly into the src attribute of an <img> tag, giving your user an instant thumbnail preview without a single call to the server.
What Is the Best Way to Show Upload Progress?
This is a classic problem. The modern fetch API, for all its improvements, doesn't have a native way to track upload progress. So, we turn back to the trusty XMLHttpRequest (XHR) object.
You can wrap your upload logic in an XHR and listen for the xhr.upload.onprogress event. This event gives you loaded and total properties, which is all you need to calculate a percentage and feed it to a UI progress bar. For large files, this feedback is crucial. If you're looking for more ways to enhance the user experience around document handling, our guide on how to embed a PDF in HTML has some useful patterns.
Is
multipart/form-datastill necessary with modern APIs?Yes. Even when you use
FormDataandfetchin JavaScript, the browser is still packaging and sending the request with theContent-Typeheader set tomultipart/form-dataunder the hood. This encoding remains the fundamental web standard for handling requests that contain files.
Need to extract structured data from your uploaded PDFs? With OkraPDF, you can turn bank statements, invoices, and financial filings into clean JSON or CSV with a single API call. Try our PDF extraction APIs today.