uer3ow
Last Updated: January 10, 2017
·
71.32K
· barneycarroll
B0b05407bf5fe02b6563b0fb39be46b4

Total input[type=file] style control with pure CSS

If you search for a solution to the common problem of how to get full appearance control over an <input type="file"/>, the result will probably fit into one of 3 categories:

  • Requires Javascript.
  • Doesn't work in a major browser.
  • Doesn't actually provide complete stylistic control.

That bill certainly fit every single answer I found on StackOverflow. But you can do this with pure CSS. It requires a single wrapping element to hook the styles onto (the input itself is hidden, since its styles are so limited/limiting). Semantics nazis will probably want to make this a <label/> — and by the way, there's nothing wrong with having multiple labels per element. Look at the spec. Now look at me. Yeah. Anyway:

CSS

.fileContainer {
    overflow: hidden;
    position: relative;
}

.fileContainer [type=file] {
    cursor: inherit;
    display: block;
    font-size: 999px;
    filter: alpha(opacity=0);
    min-height: 100%;
    min-width: 100%;
    opacity: 0;
    position: absolute;
    right: 0;
    text-align: right;
    top: 0;
}

HTML

<label class="fileContainer">
    Click here to trigger the file uploader!
    <input type="file"/>
</label>

TL;DR: Check out my fiddle for a demo and star my gist for future reference.

Is this buggy? Is there an even simpler way to do it? Leave a comment.

3 Responses
Add your response

8507

This is great, I guess the only downside to this approach is there is no confirmation of the file the user has selected! Is there a way to achieve this as well? Thanks

over 1 year ago ·
9354
720b186f7823ea92442556243041c3cb

Great solution! Thanks!

over 1 year ago ·
9359
B0b05407bf5fe02b6563b0fb39be46b4

@jaydeesigns sorryfor leaving this reply late — writing this here for posterity in case anyone else faces the same problem.

Yup, one of the tradeoffs is you have to obscure whatever useful parts of the input are there too. It's worth noting that feedback on the selected file is not at all standardized, but you can extract whatever the browser will allow using the following Javascript (where fileInput is a reference to the file input):

fileInput.value;

If I'd selected the file at D:\some\thing\foo.bar the output would be:

Firefox: 'foo.bar',
Chrome:  'C:\fakepath\foo.bar',
IE:      'D:\some\thing\foo.bar'

If you wanted to standardise that, you can extract the only reliable bit (the file name) by applying a regular expression which strips out any sequence of characters followed by a slash:

fileInput.value.replace(/([^\\]*\\)*/,'');

In such a way, you could update the label text (for example), by using jQuery:

$( '.fileContainer [type=file]' ).on( 'click', function updateFileName( event ){
    var $input = $( this );

    setTimeout( function delayResolution(){
        $input.parent().text( $input.val().replace(/([^\\]*\\)*/,'') )
    }, 0 )
} );

Note I didn't use the change event above because IE will only fire that once the user has navigated (tabbed or clicked) away from the input after using it. Instead we listen for the click event (which will trigger on keyboard activation too), and use a setTimeout to make the function resolve as soon as possible (zero milliseconds): in this way, the user clicks, the dialogue has time to open, and Javascript only executes when the user has finished inputting.

over 1 year ago ·