Bootstrap logo

Whipping File Inputs Into Shape with Bootstrap 3

There are many, many, many ways to hack a file input so it looks and behaves consistently across all browsers. There’s even a pretty slick plugin to help get the job done. Unfortunately, most of these solutions are cumbersome, prone to cross-browser issues, and require JavaScript. Today, we would like to propose a more fundamental approach for file inputs in Bootstrap.

Back to the basics

Let’s start by making a fake button with a nested file input:

<span class="btn btn-default btn-file">
    Browse <input type="file">
</span>

And then apply some CSS:

.btn-file {
    position: relative;
    overflow: hidden;
}
.btn-file input[type=file] {
    position: absolute;
    top: 0;
    right: 0;
    min-width: 100%;
    min-height: 100%;
    font-size: 100px;
    text-align: right;
    filter: alpha(opacity=0);
    opacity: 0;
    outline: none;
    background: white;
    cursor: inherit;
    display: block;
}

So far so good. Not only will the “button” trigger the file input, but it will also acquire the :hover and :active pseudo classes so it behaves like a real button.

You can use these buttons like you normally would…by themselves, in a button group, or even in an input group.

Providing feedback

Now with the hard part out of the way, it’s a good practice to provide users with a bit of feedback about their selection. A touch of jQuery magic will keep an eye on your file inputs and fire an event called fileselect when a file is chosen:

$(document).on('change', '.btn-file :file', function() {
    var input = $(this),
        numFiles = input.get(0).files ? input.get(0).files.length : 1,
        label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
    input.trigger('fileselect', [numFiles, label]);
});

Here’s an example to demonstrate the event:

$(document).ready( function() {
    $('.btn-file :file').on('fileselect', function(event, numFiles, label) {
        console.log(numFiles);
        console.log(label);
    });
});

You can use the numFiles or label parameter to show users the name of the file that was selected and, if applicable, how many. Alternatively, you could elect to use the standard change event and handle the label yourself.

This method was tested to work in IE8–IE11 and recent versions of Chrome, Safari, Firefox, and Opera.

See it in action

See the Pen vAgmd by Cory LaViska (@claviska) on CodePen.

About the author

Cory LaViska is a founder, web developer, and bootstrapper based in New Hampshire. His current focus is on Surreal CMS, an awesome SaaS content management service for web designers. Need to get in touch? You can connect with him on Twitter.

Comments

  1. Nathan Loding says:

    This is a great set up, and a perfect styling for the file inputs in Boostrap, but I found one bug in Firefox. If you tab to the input group button (must tab, clicking works fine) the text of the button disappears. I have not found the cause yet. Anyone know what would be causing that? It appears to work fine in Chrome and IE.

    • Cory LaViska says:

      Can you post a minimal test case on CodePen? I haven’t heard of this before and a lot of people use it. Chances are, there’s something in your implementation that’s interfering and a minimal test case may uncover that for you. If not, we’ll at least have something to work with to get it fixed

      • Nathan Loding says:

        Cory – it happens with your CodePen linked in the article. I thought it might be my implementation so I went back to the source

        I’ve tested in Firefox 31 on both Windows and OSX. To replicate, click on the text input in the input group then Shift+Tab back to the button. The text disappears.

        • Cory LaViska says:

          This answer has a description of the problem and led me to a fix. Change font-size to 100px. That value should work fine in most implementations. Thanks for spotting that! (The code above has been updated.)