How to style "input file" with CSS3 / Javascript?

Viewed 98220

I would like to style <input type="file" /> using CSS3.

Alternatively, I would like user to press on a div (that I will style) and this will open the Browse window.

Is that possible to do that using HTML, CSS3, and Javascript / jQuery only ?

12 Answers

Here's an example that I'm using that utilizes jQuery, I've tested against Firefox 11, and Chrome 18, as well as IE9. So its pretty compatible with browsers in my book, though i only work with those three.

HTML

Here's a basic "Customizable" HTML structure.

<span>
    File to Upload<br />
    <label class="smallInput" style="float:left;">
        <input type="file" name="file" class="smallInput" />
    </label>
    <input type="button" class="upload" value="Upload" style="float:left;margin-top:6px;margin-left:10px;" />
</span>

CSS

Here's a sample of my CSS

label.smallInput {
    background:url(images/bg_s_input.gif) no-repeat;
    width:168px;
}

JavaScript

This is the heavy lifter.

/* File upload magic form?? */
$("input.smallInput[type=file]").each(function(i){
    var id      = "__d_file_upload_"+i;
    var d_wrap  = $('<div/>').attr('id',id).css({'position':'relative','cursor':'text'});

    $(this).wrap(d_wrap).bind('change blur focus keyup click',function(){
        $("#"+id+" input[type=text]").val($(this).val());
    }).css({'opacity':0,'zIndex':9999,'position':'absolute'}).removeClass('smallInput');

    obj = $(this);

    $("#"+id).append($("<input/>").addClass('smallInput').attr('type','text').css({'zIndex':9998,'position':'absolute'}).bind('click',function(e){obj.trigger('click');$(this).blur();}));
    obj.closest('span').children('input.upload[type=button]').bind('click',function(e){
        obj.trigger('click');
        $(this).blur();
    });
});
/* ************************ */

Explanation

The HTML is pretty straight forward, just a simple element, i include the button so it can be named independently from the rest, sure this could be included in the JavaScript, but simply put, I'm a bit on the lazy side. The code searches for all inputs with a class of smallInput that have the type of file this allows you to define default HTML and fallback form structure in case a browser decides to be a pain.

This method only uses JavaScript to ensure delivery, it does not alter any browser behaviors in regards to the file input.

You can modify the HTML and JavaScript to make it very robust, this code suffices my current project so i doubt I'll be making any changes to it.

Caveats

  • Different browsers treat the value of the file input differently, which in chrome results in c:\fakeroot\ on windows machines.
  • Uses anonymous functions, (for lack of a better word) which means if you have too many file inputs you can cause the browser to behave slowly on processing.

Ran into the same issue today, but it seems there's an easy way to have your own styles - hide the input, and style the associated label:

<div class="upload">
  <label for="my-input"> Upload stuff </label>
  <input type="file" id="my-input" name="files[]" />
</div>

CSS:

.upload input{
  display: none;
}

.upload label{
  background: DarkSlateBlue;
  color: white;
  padding: 5px 10px;
}

Works in latest Chrome, Firefox and IE 10. Didn't test others

Here is a solution with a text field where the user types in the (relative) pathname of the file copy on the server (if authorized) and a submit button to browse the local system for a file and send the form:

<form enctype="multipart/form-data" action="" method="post">
<input type="hidden" name="MAX_FILE_SIZE" value="1000000" />
<p><input type="file" name="upload_file" id="upload_file" size="40"/></p>
<p><input type="text" id="upload_filename" name="upload_filename" size="30" maxlength="100" value="<?php echo htmlspecialchars($filename, ENT_COMPAT, 'UTF-8'); ?>"/>
<input type="submit" class="submit submit_upload" id="upload_upload" name="upload_upload" value="Upload"/></p>
</form>

The scripting part hides the file input, clicks it if the user clicks on the submit button, submits the form if the user has picked up a file. If the user tries to upload a file without entering a filename, the focus is first moved to the text field for the filename.

<script type="text/javascript">
var file=$('#upload_file');
var filename=$('#upload_filename');
var upload=$('#upload_upload');

file.hide().change(function() {if (file.val()) {upload.unbind('click').click();}});

upload.click(function(event) {event.preventDefault();if (!filename.val()) {filename.focus();} else {file.click();}});
</script>

Simply style the submit button for a perfect result:

.submit {padding:0;margin:0;border:none;vertical-align:middle;text-indent:-1000em;cursor:pointer;}
.submit_upload {width:100px;height:30px;background:transparent url(../images/theme/upload.png) no-repeat;}
Related