A wheelchair symbol painted on pavement holding a file input form control

Style an Accessible ‘File Upload’ Button

The default HTML file upload control — created with <input type="file"> — has a different look depending on your browser and operating system. This is a problem for designers wanting to create a cohesive brand where all of the form fields have a similar look and feel.

It’s actually fairly simple to replace the default file upload control with your own custom button. The problem is making it accessible as well.

Boilerplate HTML

Let’s start with some basic HTML. We’re going to assume this is a job application form where the user needs to upload a resume. We’ll have a label that says, “Upload Résumé,” followed by the file upload control.

<label for="resume">Upload Résumé</label>
<input type="file" id="resume">

Styling it Up

First, we want to hide the file upload control visually. We’ll do this in an accessible fashion with the following CSS.

.sr-only {
  position: absolute;
  margin: -1px;
  width: 1px;
  height: 1px;
  border: 0;
  clip: rect(0, 0, 0, 0);
  overflow: hidden;

The .sr-only class we created is for screen readers and is similar to the class used by Bootstrap for hiding content. To hide the file upload control, we need to add that class to our control.

<input type="file" id="resume" class="sr-only">

Now, we can style our label to look like a button.

.btn {
  display: inline-block;
  padding: .5rem 1rem;
  border-radius: .25rem;
  color: #fff;
  background-color: #25a;
  cursor: pointer;

Don’t forget to add the .btn class to the label.

<label for="resume" class="btn">Upload Résumé</label>

If you try clicking the button now, you’ll see that it works as expected, showing a file selection dialog box. There’s just one problem: if you navigate the page with a keyboard, there’s no indicator to show when the control has focus. That’s because we hid the input element. You can still tab to it, but it’s invisible.

Making it Keyboard Friendly

At this point, we could resort to JavaScript to add a focus indicator to the label when the input receives focus. But, let’s see what we can do with just HTML and CSS.

We’re going to reverse the order of our two HTML elements and add a couple ARIA attributes so that it still makes sense to screen readers.

<input type="file" id="resume" class="sr-only" aria-label="Upload Résumé">
<label for="resume" class="btn" aria-hidden="true">Upload Résumé</label>

With the reversed order, we can now take advantage of the CSS sibling selector to add the focus indicator.

[type=file]:focus + .btn {
  outline: 5px solid #a52;

The outline property style we picked is just an example. Make sure to use a focus indicator style that matches the rest of your form controls.

There we have it! An easily styled, accessible file upload control.

See the Pen Accessible File Upload Button by Thomas Higginbotham (@thomashigginbotham) on CodePen.

Leave a Reply

Your email address will not be published. Required fields are marked *