Thursday, January 21, 2010

CSS Style <input type=”file”> tags


Inputs of type=”file” are probably the hardest tags to style in html. Due to security issues browsers don’t allow you to change it too much.
Of course we have tricks but since each browser makes its own implementation of the control (and it’s poorly documented stuff) the tricky part is to find something that works for all browsers.
If you google for it you’ll find a few tutorials that are hard to understand and use too much javascript, jquery and css.
I found a relatively simple way to achieve this and I’ll try to make it easy to understand. It goes in 4 steps.
STEP 1 – Create a text box and a input “type file”
Start with a textbox and a div with a input “type file” inside of it. The div should be the size of the “browse…” button that you want to use.
The only tricky part for now is the overflow property in the css class of the div being set to hidden. That causes the overflowing content of the div to be hidden from sight. See it in the screenshot.
html:
<input id="fileName" class="file_input_textbox" readonly />
 
<div class="file_input_div">
  <input type="file" />
</div>
css:
.file_input_textbox
{
 float: left
}

.file_input_div
{
  position: relative; 
  width: 100px; 
  height: 23px; 
  overflow: hidden;
}
screenshot:
image
STEP 2 – The fun part: oversize the input  “type=file”
Now we have to make the button part of the input “type=file” show in the div and completely fill it. Aligning it to the right is now enough because the different browsers act differently in this case.
So, the big trick in this tutorial? Oversize the control. How? Just set its font size to an absurd size (probably 30px will be enough, though).
html:
<input type="text" id="fileName" class="file_input_textbox" readonly="readonly">

<div class="file_input_div">
  <input type="file" class="file_input_hidden"  />
</div>
css:
.file_input_hidden
{
  font-size: 23px; 
  position: absolute; 
  right: 0px; 
  top: 0px; 
  opacity: 0; 
}
screenshot:
image
STEP 3 – Make the input “type=file” invisible and put your customized button behind it.
Making the file input invisible doesn’t mean that you cant click it. So, make it invisible, put a customized button behind it.
That way, you will see your customized button but when you click it, you will in fact be clicking the real (invisible) browse button (the one that is oversized, overflowing, over the customized button, remember?)
You can customize your browse button by changing the “file_input_button” css class.
html:
<input type="text" id="fileName" class="file_input_textbox" readonly="readonly">
 
<div class="file_input_div">
  <input type="button" value="Search files" class="file_input_button" />
  <input type="file" class="file_input_hidden" />
</div>

css:
.file_input_button
{
 width: 100px; 
 position: absolute; 
 top: 0px;
 background-color: #33BB00;
 color: #FFFFFF;
 border-style: solid;
}

.file_input_hidden
{
 font-size: 45px; 
 position: absolute; 
 right: 0px; 
 top: 0px; 
 opacity: 0; 
 
 filter: alpha(opacity=0); 
 -ms-filter: "alpha(opacity=0)"; 
 -khtml-opacity: 0; 
 -moz-opacity: 0;
}
screenshot:
image
STEP 4 – Final step: Fill the text box with the name of the selected file
If you tried the previous steps, will have noticed that after you select a file, nothing shows in the text box. That’s because the file name is indeed being written in the hidden input “type=file”.
So, in this final step you shall add a simple javascript instruction to the onchange event of the input “type=file” tag. That instruction copies its value (the filename) to the text box.
html:
<input type="text" id="fileName" class="file_input_textbox" readonly="readonly">
 
<div class="file_input_div">
  <input type="button" value="Search files" class="file_input_button" />
  <input type="file" class="file_input_hidden" onchange="javascript: document.getElementById('fileName').value = this.value" />
</div>
And… voilá. It should be working. I’ve tested it in Firefox 3, IE6, IE7, IE8, Opera 10, Chrome 3 and it worked perfectly in all of them.

The complete solution
So, here is the complete code (css and html all in one):
//css
.file_input_textbox
{
 float: left
}

.file_input_div
{
 position: relative; 
 width: 100px; 
 height: 23px; 
 overflow: hidden;
}

.file_input_button
{
 width: 100px; 
 position: absolute; 
 top: 0px;
 background-color: #33BB00;
 color: #FFFFFF;
 border-style: solid;
}

.file_input_hidden
{
 font-size: 45px; 
 position: absolute; 
 right: 0px; 
 top: 0px; 
 opacity: 0; 
 
 filter: alpha(opacity=0); 
 -ms-filter: "alpha(opacity=0)"; 
 -khtml-opacity: 0; 
 -moz-opacity: 0;
}

 
//html
<input type="text" id="fileName" class="file_input_textbox" readonly="readonly">
 
<div class="file_input_div">
  <input type="button" value="Search files" class="file_input_button" />
  <input type="file" class="file_input_hidden" onchange="javascript: document.getElementById('fileName').value = this.value" />
</div>
There. I hope it works for you as well as it did for me. If you find it doesn't work that well, feel free to let me know.

And if you like playing android games, why not check my new game "Up Up n' Roll Away" in the Play Store:
https://play.google.com/store/apps/details?id=com.BubbleBoy.UpUpRollAway


38 comments:

GlobeTrekker said...

Hi,

I did as you described and it works (uploads file), but the problem I got is when you choose the file it doesn't show the path, the text field stays empty.

Any ideas?

Vidma

tiago said...

GlobeTrekker, I just tested my code and it works flawlessly in the latest versions of IE, Firefox, Opera, Chrome and Safari. The difference being that IE8 shows the complete path of the file and the others show only its name.

Maybe you could post your html and tell me which browser (and version) you're using. I'll try to fix it, ok?

Thanks for your comment.

GlobeTrekker said...

Hello,

here is the code, I am trying to implement joomGallery image upload page.


here is the part od PHP document where you have the upload form

"div class="jg_uprow""
"div class="jg_uptext""
"?php echo JText::_('JGS_PICTURE_PATH'); ?":
"/div"


"input type="text" id="fileName" class="file_input_textbox" readonly="readonly"
"div class="file_input_div""

"?php echo <""input type='button' value='Select file' class='file_input_button'/"
"input type ='file' name = 'arrscreenshot[$i]' class='file_input_hidden' onchange='javascript: document.getElementById('fileName').value = this.value'/""; ?"

"/div"
"/div"

I have changed "<" to " " ".

Here is the CSS

/* upload file */
.file_input_textbox {
width: 170px;
height: 16px;
margin: 0px;
padding: 2px;
font: 11px Tahoma, Geneva, sans-serif;
color: #f1f1e2;
background: #b5c532;
border: 1px solid #93ad1c;
float: left;
}
.file_input_div {
position: relative;
width: 100px;
height: 23px;
overflow: hidden;
}
.file_input_button {
width: auto;
height: 22px;
padding: 2px;
font: 11px/20px Tahoma, Geneva, sans-serif;
color: #f1f1e2;
text-align: center;
background: #b5c532;
border: 1px solid #93ad1c;
position: absolute;
top: 0px;
left: 5px;
cursor: pointer;
outline: none;
}
.file_input_hidden {
font-size: 45px;
position: absolute;
right: 0px;
top: 0px;
opacity: 0;

filter: alpha(opacity=0);
-ms-filter: "alpha(opacity=0)";
-khtml-opacity: 0;
-moz-opacity: 0;
}


As I have mentioned before, everything works (the images are uploaded) but only thing is the invisible path in the impute field.

I have tested on FF 3.5.7

Regards,
Vidma

tiago said...

Hi Vidma,

I've tested your code and found something a little wrong. You have to find the following text in your code:

onchange='javascript: document.getElementById('fileName').value = this.value'

and replace it with:

onchange=\"javascript: document.getElementById('fileName').value = this.value\"

I've tested it and it worked fine.

Let me know if it worked for you too. Good luck.

GlobeTrekker said...

Hi,

Thanks, it worked out!

Only thing that I have 3 input boxes and when you place file in the second one it change it in the firs. So it’s impossible to fill all 3 input boxes.

Also only works the button that opens your computer window, if you click inside the input box it does nothing.

Any, thanks a lot!

Vidma

Unknown said...

Hi Vidma,
I test your code its working but having one issue in IE8. In IE8 its open the file dialog box on double click on single clink does nothing.
Imran Arshad

Unknown said...

Amazing, simple and clean solution, works perfect in IE6-IE8 and Firefox. Quirksmode's heavy javascript solution is a joke compared to this.

Unknown said...

Hi,
If i want to add a text or label (for example: (Optional))after the button , is it possible?

Thanks

pepe said...

thanks... very good tutorial

Mike Lohrman said...

Taigo,

Ran into this problem for the first time today. Everything you have shared works up until the javascript that puts the filename into the text box. I keep getting an error "Uncaught TypeError: Cannot set property 'value' of null"

Any ideas?

Unknown said...

Thanx a lot- your code saved me a lot of work ;-)))

WebBlogger said...

well i've tried your code but still there's a problem on browsing a file it doesn't give the full path like:on fire fox gives you only the file name and IE says C:\fakepath\filename.gif

Deepak said...

Your Code Works well in all the browsers except opera 10.10. It doesnt give full path.instead it gives C:\fakepath\filename.gif. Let me know if there is any work around for this.

Pawel said...

Hey Tiago. Good work!
There is one question: is there any idea to make this customized browse button working as regular button? What it mean - eg. after click on customized button, it should collapse, in your solution it behave like static image - doesn't collapse, there is no interaction but it's work (shows browse file window).

Me said...

good work thanks for help me.
i found another site having good page rank tips and tutorials.that is "Tutorials99"
see below link
http://www.tutorials99.com

techtick said...

excellent tutorial. love you for that

Unknown said...

Well written,explained tutorial... worked for me .It really wonderful to find this article after going through some bit complex solution.Thanks a lot

Unknown said...

I am too running into same problem like most of the people above...unable to see the path name in textbox though the file is getting uploaded successfully.After choosing the file the textbox doesnt get populated with the name of the file i.e step 4th isn;t working on both Mozilla 3.0 and IE 8.0.Any help is appreciable.

Ketan said...

i have used same code as per above you suggest but cant show path in textbox.

Can you help me.

Thanks
Ketan

Carson said...

Hey,
I used this method in combination with Contact Form 7 and it works nearly flawlessly.
My issue is that the file selector doesn't pop up in IE. Any idea why that may be? Here's the link - http://www.carsonshold.com/contact/

Unknown said...

use this script if having problems displaying the file in the input

this.form.fileName.value = this.value;

© http://www.kavoir.com/2009/02/styling-file-upload-select-input-control-input-typefile.html/comment-page-1#comment-14134

Unknown said...

Hi,

I am using this code to upload a picture. It looks fine and let you search for the file. However the path that appear in the box says "fakepath". Not sure what is creating this. Any ideas?

In IE8 the path looks fine but still does not load the picture. I guess the code is not connected correctly. I can send you the code to have a look.

tiago said...

Richard,

Sure, send me the code and I'll try to take a look at it (when I can).

Cheers.

Unknown said...

I found the solution to my problem. the "name=" is not mentioned in your code before "onchange=".

In fact it does not matter the order is just that it is not mentioned in that line. Hope it help others.

Sachitra said...

Hi,

Is there any way to set some default path say for example C:/test something on click of the browse button

Sanjay Ratan said...

Hi Tiago Epifânio,

Thanks a lot for sharing your code to customize file input type...

Sanjay

creator said...

Thanks, works perfect.

Anthony said...

THANK YOU. I've been searching for a method of doing this without any Flash and with the ability to preserve the text field part. This is the only solution I've come across that does both of those things and appears to work well across browsers and platforms.

Unknown said...

How can I get this to work with multiple files? When I choose 2 files, it just shows the last one.

Thanks

Hayko said...

How can I remove the fakepath on the file path

John Velasco said...

Any solution to the C:\fakepath\ issue? That would be super helpful! Otherwise, great tutorial!

Jan a Eva Lejskovi said...

Hey guys,
C:\fakepath\ resolved
This works for me
onchange="javascript: this.form.fileName.value=((this.value.replace(/^.*[\/\\]/g, '')).split('..',2));

As seen on Práce v zahraničí

JP said...

Hi Tiago,
I try to use your code but there's a problem. on Safari brownser the button to choose the file is static when click on it doesn't open to choose the files. Please could help you. thanks in advance.
this what I have done.
CSS script didn't change

HTML
table border="1" align="right" bgcolor="#CDDADA" width="260">
tr
td
form method="post" action="?subpage=upload" enctype="multipart/form-data" onsubmit="return FormValidate()"

input type="text" name="imagefile" id="fileName" class="file_input_textbox" readonly="readonly"
div class="file_input_div"
input type="button" value="brownse" class="file_input_button"
input type="file" name="imagefile" class="file_input_hidden" onchange="javascript: document.getElementById('fileName').value = this.value"
/div


Comments about image


input type="text" name="comments"
onkeydown="LimitInput(this.form.comments,this.form.textcount,20);"
onkeyup="LimitInput(this.form.comments,this.form.textcount,20);"

input name="Upload" type="submit" value="Upload" class="form">

/form
/td
/tr

/table

tiago said...

Thanks JP. I haven't reviewed this article in a while. One of these days I have to update it.

Pawel said...

It isn't secret that your workaround could be used for translations. Due to this, text on button (also width) is changing for each language.

After button 'Select file', usually is added button like 'Add file' or 'Send'. Current solution could lead to some problems with display 'Select file' button with longer texts or wider fonts (e.g. for CN or JP).

I suggest to remove from .file_input_button and .file_input_div line 'width: 100px;' and to add to .file_input_div line 'display: inline-block;' instead.

Phpwebdev said...

Hi

Thank you so much

Helped a lot.

Good tutorial

zeesh said...

Just awsome article , it helped me alottttttt, thanks

Azad Bharti said...

Thanks , it realy helped me