Michele Nasti

Thoughts on what I learn

How to style a button to upload a file

This is what I'm doing right now at work: trying to style an input button to upload a file.

So, if you simply type the code like this:

<pre class="lang:default decode:true "><input type="file"></pre>

this is what you get:

<img class="aligncenter wp-image-84 size-full" src="https://i1.wp.com/michelenasti.com/uploads/2015/01/upload-no-style.png?fit=215%2C44" alt="upload-no-style" data-recalc-dims="1" />The problem is: how do you style the button ( written here in Italian, "scegli file" - "choose file") to match the style of your website?

For example, in my works I use bootstrap like half dozen million of people of the world does. I want the style of this button to match the style of the others. Also, I don't want to see the "nessun file selezionato" ("no file selected") written aside (it can't be styled too!).

The solution

This is something I have discovered on StackOverflow and by now it is my favorite hack.

<pre class="lang:default decode:true"><div class="form-group"> <label for="inputFile" class="btn btn-primary"> <input id="inputFile" type="file" style="display:none;"> Select File </label> </div></pre>

This is how it is rendered by the majority of browsers:

<img class=" size-full wp-image-85 aligncenter" src="https://i0.wp.com/michelenasti.com/uploads/2015/01/upload-button-styled.png?fit=162%2C121" alt="upload-button-styled" data-recalc-dims="1" />The first "this is a button" is a normal html <span class="lang:default decode:true crayon-inline "><button></span> element. the second is the file uploader button.

How the hack works?

When you wrap a <span class="lang:default decode:true crayon-inline "><label></span> around an <span class="lang:default decode:true crayon-inline"><input></span> element, if you click on the label, the click is propagated to the input element pointed by the <span class="lang:default decode:true crayon-inline ">for="..."</span> attribute (matching the input id).

Another help is coming from the <span class="lang:default decode:true crayon-inline ">style="display:none;"</span> attribute. It will hide the input element from the screen, so that we only see the label for the input.


Boring part. It seems that it doesn't work very well with IE8 and before. Have a look on Stack Overflow on how to make it work. I don't care, since I don't use IE and I generally target my work to the latest browsers and platforms.