When building applications with HTML, you may eventually come to a point where you need to allow users to upload files. Surprisingly, it's not quite as straightforward as you might assume.
In this post, we'll look at all things you need to support file uploads in HTML.
How to Access Files
The very first step is accessing a file to upload. Unfortunately, or rather, fortunately, browsers can’t access our file systems. If they did, it would be a major security concern.
There is work being done on the File System Access API, but it’s experimental and will be limited access, so let’s just pretend it doesn’t exist.
Accessing a file requires user interaction, which means we need something in the UI for the user to interact with. Conveniently, there is the input element with a file
<input type="file" />
On its own, a file input isn’t very useful. It allows a user to select a file from their device, but that’s about it.
The input will also need a
<label> to make it accessible for assistive technology, an
id attribute to associate it with the label, and a
name attribute in order to include its data along with the HTTP request.
<form> <label for="file">File</label> <input id="file" type="file" /> <button>Upload</button> </form>
Looks good 👍.
Doesn’t work good, though 👎.
How to Include a Request Body
If we watch the network tab as we submit the form, we can see that it generates a GET request, and the payload is sent as a query string that looks like this: “
?name=filename.txt”. It’s essentially a key-value pair, with the key being the input
name and the value being the name of the file.
This is sent as a string.
Not quite what we’re going for here.
We can’t actually send a file using a GET request because you can’t put a file in the query string parameters. We need to put the file in the body of the request.
<form method="post"> <label for="file">File</label> <input id="file" name="file" type="file" /> <button>Upload</button> </form>
Now, if we explore that request, we can see that we are making a post request. We can also see that the request has a payload containing the form’s data. Unfortunately, the data is still just a key-value pair with the input
name and the filename.
How to Set the Content-Type
We’re still not actually sending the file, and the reason has to do with the request “
By default, when a form is submitted, the request is sent with a
application/x-www-form-urlencoded. And unfortunately, we can’t send the binary file information as URL encoded data.
<form method="post" enctype="multipart/form-data"> <label for="file">File</label> <input id="file" name="file" type="file" /> <button>Upload</button> </form>
Now, if we submit the form one more time, we can see the request uses the POST method and has the
Content-Type set to
multipart/form-data. In Chromium browsers, you’ll no longer see the request payload, but you can see it in the Firefox DevTools under the request Params tab.
We did it!
With all that in place, we can upload files using HTML. To re-iterate, sending files with HTML requires three things:
- Create an input with the
typeof file to access the file system.
- Use a form with
method="post"to include a body on the request.
- Set the request’s