[Html] Styling an input type=“file” button


Answers

You don't need JavaScript for this! Here is a cross-browser solution:

See this example! - It works in Chrome/FF/IE - (IE10/9/8/7)

The best approach would be to have a custom label element with a for attribute attached to a hidden file input element. (The label's for attribute must match the file element's id in order for this to work).

<label for="file-upload" class="custom-file-upload">
    Custom Upload
</label>
<input id="file-upload" type="file"/>

As an alternative, you could also just wrap the file input element with a label directly: (example)

<label class="custom-file-upload">
    <input type="file"/>
    Custom Upload
</label>

In terms of styling, just hide1 the input element using the attribute selector.

input[type="file"] {
    display: none;
}

Then all you need to do is style the custom label element. (example).

.custom-file-upload {
    border: 1px solid #ccc;
    display: inline-block;
    padding: 6px 12px;
    cursor: pointer;
}

1 - It's worth noting that if you hide the element using display: none, it won't work in IE8 and below. Also be aware of the fact that jQuery validate doesn't validate hidden fields by default. If either of those things are an issue for you, here are two different methods to hide the input (1, 2) that work in these circumstances.

Question

How to style the input type="file" button.




A really clever solution using jQuery that works in all older browsers as well as in the new ones, I found here. It takes care of all the styling and click() problems, using the actual file browse button. I made a plain javascript version: fiddle The solution is as simple as genius: make the file-input invisible, and use a piece of code to place it under the mousecursor.

<div class="inp_field_12" onmousemove="file_ho(event,this,1)"><span>browse</span>
<input id="file_1" name="file_1" type="file" value="" onchange="file_ch(1)">
</div>
<div id="result_1" class="result"></div>


function file_ho(e, o, a) {
    e = window.event || e;
    var x = 0,
    y = 0;
    if (o.offsetParent) {
        do {
        x += o.offsetLeft;
        y += o.offsetTop;
        } while (o = o.offsetParent);
    }
var x1 = e.clientX || window.event.clientX;
var y1 = e.clientY || window.event.clientY;
var le = 100 - (x1 - x);
var to = 10 - (y1 - y);
document.getElementById('file_' + a).style.marginRight = le + 'px';
document.getElementById('file_' + a).style.marginTop = -to + 'px';
}

.inp_field_12 {
position:relative;
overflow:hidden;
float: left;
width: 130px;
height: 30px;
background: orange;
}
.inp_field_12 span {
position: absolute;
width: 130px;
font-family:'Calibri', 'Trebuchet MS', sans-serif;
font-size:17px;
line-height:27px;
text-align:center;
color:#555;
}
.inp_field_12 input[type='file'] {
cursor:pointer;
cursor:hand;
position: absolute;
top: 0px;
right: 0px;
-moz-opacity:0;
filter:alpha(opacity: 0);
opacity: 0;
outline: none;
outline-style:none;
outline-width:0;
ie-dummy: expression(this.hideFocus=true);
}
.inp_field_12:hover {
background-position:-140px -35px;
}
.inp_field_12:hover span {
color:#fff;
}



These answers are nice, and they all work for very specific use cases. That is to say, they are opinionated.

So, here's an answer that assumes nothing, but will work no matter how you modify it. You can change design with css, add javascript to maybe show a file name on change, etc. it will still always work.

Code:

Here is the core css

.file-input{
  pointer-events: none;
  position: relative;
  overflow: hidden;
}
.file-input > * {
  pointer-events: none;
}
.file-input > input[type="file"]{
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  opacity: 0;
  pointer-events: all;
  cursor: pointer;
  height: 100%;
  width: 100%;
}

and the core html:

<div class="file-input">
  <input type="file"/>
</div>

As you can see, we are forcing any pointer event(click) that happens on the .file-input element, or any of its children, to be proxied to the file input. This is because the file input is positioned absolute and will consume the width/height of the container always. You can therefore customize to fit your need. style the wrapper into a button, use some js to display file name on select, etc. nothing will break so long as the above core code remains intact.

As you will see in the demo, i have added a span with text "Select file" and a class with extra styles to style the .file-input div. This should be the canonical starting point for anyone intending to create a custom file upload element.

Demo:JSFIDDLE




This is simple with jquery. To give a code example of Ryan's suggestion with a slight modification.

Basic html:

<div id="image_icon"></div>
<div id="filename"></div>
<input id="the_real_file_input" name="foobar" type="file">

Be sure to set the styling on the input when you're ready: opacity: 0 You can't set display: none because it needs to be clickable. But you can position it under the "new" button or tuck in under something else with z-index if you prefer.

Setup some jquery to click the real input when you click the image.

$('#image_icon').click(function() {
    $('#the_real_file_input').click();
});

Now your button is working. Just cut and paste the value when changed.

$('input[type=file]').bind('change', function() {
    var str = "";
    str = $(this).val();
    $("#filename").text(str);
}).change();

Tah dah! You may need to parse the val() to something more meaningful but you should be all set.




Here is a solution, that also shows the chosen file name: http://jsfiddle.net/raft9pg0/1/

HTML:

<label for="file-upload" class="custom-file-upload">Chose file</label>
<input id="file-upload" type="file"/>
File: <span id="file-upload-value">-</span>

JS:

$(function() {
    $("input:file[id=file-upload]").change(function() {
        $("#file-upload-value").html( $(this).val() );
    });
});

CSS:

input[type="file"] {
    display: none;
}

.custom-file-upload {
      background: #ddd;
      border: 1px solid #aaa;
      border-top: 1px solid #ccc;
      border-left: 1px solid #ccc;
      -moz-border-radius: 3px;
      -webkit-border-radius: 3px;
      border-radius: 3px;
      color: #444;
      display: inline-block;
      font-size: 11px;
      font-weight: bold;
      text-decoration: none;
      text-shadow: 0 1px rgba(255, 255, 255, .75);
      cursor: pointer;
      margin-bottom: 20px;
      line-height: normal;
      padding: 8px 10px; }



Here we use a span to trigger input of type file and we simply customized that span, so we can add any styling using this way.

Note that we use input tag with visibility:hidden option and trigger it in the span.

.attachFileSpan{
color:#2b6dad;
cursor:pointer;
}
.attachFileSpan:hover{
text-decoration: underline;
}
<h3> Customized input of type file </h3>
<input id="myInput" type="file" style="visibility:hidden"/>

        <span title="attach file" class="attachFileSpan" onclick="document.getElementById('myInput').click()">
        Attach file
        </span>

Reference




If you are using Bootstrap 3, this worked for me:

See http://www.abeautifulsite.net/whipping-file-inputs-into-shape-with-bootstrap-3/

.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;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />

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

Which produces the following file input button:

Seriously, check out http://www.abeautifulsite.net/whipping-file-inputs-into-shape-with-bootstrap-3/




the only way i can think of is to find the button with javascript after it gets rendered and assign a style to it

you might also look at this writeup




Maybe a lot of awnsers. But I like this in pure CSS with fa-buttons:

.divs {
    position: relative;
    display: inline-block;
    background-color: #fcc;
}

.inputs {
    position:absolute;
    left: 0px;
    height: 100%;
    width: 100%;
    opacity: 0;
    background: #00f;
    z-index:999;
}

.icons {
    position:relative;
}
<div class="divs">
<input type='file' id='image' class="inputs">
<i class="fa fa-image fa-2x icons"></i>
</div>

<div class="divs">
<input type='file' id='book' class="inputs">
<i class="fa fa-book fa-5x icons"></i>
</div>
<br><br><br>
<div class="divs">
<input type='file' id='data' class="inputs">
<i class="fa fa-id-card fa-3x icons"></i>
</div>





<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>

Fiddle: https://jsfiddle.net/zoutepopcorn/v2zkbpay/1/




Don't be fooled by "great" CSS-only solutions that are actually very browser-specific, or that overlay the styled button on top of the real button, or that force you to use a <label> instead of a <button>, or any other such hack. JavaScript IS necessary to get it working for general usage. Please study how gmail and DropZone do it if you don't believe me.

Just style a normal button however you want, then call a simple JS function to create and link a hidden input element to your styled button.

<!DOCTYPE html>
<meta charset="utf-8">

<style>
    button {
        width            : 160px;
        height           : 30px;
        font-size        : 13px;
        border           : none;
        text-align       : center;
        background-color : #444;
        color            : #6f0;
    }
    button:active {
        background-color : #779;
    }
</style>

<button id="upload">Styled upload button!</button>

<script>

function Upload_On_Click(id, handler) {
    var hidden_input = null;
    document.getElementById(id).onclick = function() {hidden_input.click();}
    function setup_hidden_input() {
        hidden_input && hidden_input.parentNode.removeChild(hidden_input);
        hidden_input = document.createElement("input");
        hidden_input.setAttribute("type", "file");
        hidden_input.style.visibility = "hidden";
        document.querySelector("body").appendChild(hidden_input);
        hidden_input.onchange = function() {
            handler(hidden_input.files[0]);
            setup_hidden_input();
        };
    }
    setup_hidden_input();
}

Upload_On_Click("upload", function(file) {
    console.log("GOT FILE: " + file.name);
});

</script>

Notice how the above code re-links it after every time the user chooses a file. This is important because "onchange" is only called if the user changes the filename. But you probably want to get the file every time the user provides it.




All rendering engines automatically generate a button when an <input type="file"> is created. Historically, that button has been completely un-styleable. However, Trident and WebKit have added hooks through pseudo-elements.

Trident

As of IE10, the file input button can be styled using the ::-ms-browse pseudo-element. Basically, any CSS rules that you apply to a regular button can be applied to the pseudo-element. For example:

::-ms-browse {
  background: black;
  color: red;
  padding: 1em;
}
<input type="file">

This displays as follows in IE10 on Windows 8:

WebKit

WebKit provides a hook for its file input button with the ::-webkit-file-upload-button pseudo-element. Again, pretty much any CSS rule can be applied, therefore the Trident example will work here as well:

::-webkit-file-upload-button {
  background: black;
  color: red;
  padding: 1em;
}
<input type="file">

This displays as follows in Chrome 26 on OS X:




Hide it with css and use a custom button with $(selector).click() to activate the the browse button. then set an interval to check the value of the file input type. the interval can display the value for the user so the user can see whats getting uploaded. the interval will clear when the form is submitted [EDIT] Sorry i have been very busy was meaning to update this post, here is an example

<form action="uploadScript.php" method="post" enctype="multipart/form-data">
<div>
    <!-- filename to display to the user -->
    <p id="file-name" class="margin-10 bold-10"></p>

    <!-- Hide this from the users view with css display:none; -->
    <input class="display-none" id="file-type" type="file" size="4" name="file"/>

    <!-- Style this button with type image or css whatever you wish -->
    <input id="browse-click" type="button" class="button" value="Browse for files"/>

    <!-- submit button -->
    <input type="submit" class="button" value="Change"/>
</div>

$(window).load(function () {
    var intervalFunc = function () {
        $('#file-name').html($('#file-type').val());
    };
    $('#browse-click').on('click', function () { // use .live() for older versions of jQuery
        $('#file-type').click();
        setInterval(intervalFunc, 1);
        return false;
    });
});



I've found a very easy method to switch the file button to a picture. You just label a picture and place it on top of the file button.

<html>
<div id="File button">
    <div style="position:absolute;">
        <!--This is your labeled image-->
        <label for="fileButton"><img src="ImageURL"></label>
    </div>
    <div>
        <input type="file" id="fileButton"/>
    </div>
</div>
</html>

When clicking on the labeled image, you select the file button.




Update Nevermind, this doesn't work in IE or it's new brother, FF. Works on every other type of element as expected, but doesn't work on file inputs. A much better way to do this is to just create a file input and a label that links to it. Make the file input display none and boom, it works in IE9+ seamlessly.

Warning: Everything below this is crap!

By using pseudo elements positioned/sized against their container, we can get by with only one input file (no additional markup needed), and style as per usual.

Demo

<input type="file" class="foo">

.foo {
    display: block;
    position: relative;
    width: 300px;
    margin: auto;
    cursor: pointer;
    border: 0;
    height: 60px;
    border-radius: 5px;
    outline: 0;
}
.foo:hover:after {
    background: #5978f8;
}
.foo:after {
    transition: 200ms all ease;
    border-bottom: 3px solid rgba(0,0,0,.2);
    background: #3c5ff4;
    text-shadow: 0 2px 0 rgba(0,0,0,.2);
    color: #fff;
    font-size: 20px;
    text-align: center;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: block;
    content: 'Upload Something';
    line-height: 60px;
    border-radius: 5px;
}

Enjoy guys!

Old Update

Turned this into a Stylus mixin. Should be easy enough for one of you cool SCSS cats to convert it.

file-button(button_width = 150px)
  display block
  position relative
  margin auto
  cursor pointer
  border 0
  height 0
  width 0
  outline none
  &:after
    position absolute
    top 0
    text-align center
    display block
    width button_width
    left -(button_width / 2)

Usage:

<input type="file">

input[type="file"]
    file-button(200px)



Here is a solution which doesn't really style the <input type="file" /> element but instead uses a <input type="file" /> element on top of other elements (which can be styled). The <input type="file" /> element is not really visible hence, the overall illusion is of a nicely styled file upload control.

I came across this problem recently and despite the plethora of answers on , none really seemed to fit the bill. In the end, I ended up customizing this so as to have a simple and an elegant solution.

I have also tested this on Firefox, IE (11, 10 & 9), Chrome and Opera, iPad and a few android devices.

Here's the JSFiddle link -> http://jsfiddle.net/umhva747/

$('input[type=file]').change(function(e) {
    $in = $(this);
    $in.next().html($in.val());
    
});

$('.uploadButton').click(function() {
    var fileName = $("#fileUpload").val();
    if (fileName) {
        alert(fileName + " can be uploaded.");
    }
    else {
        alert("Please select a file to upload");
    }
});
body {
    background-color:Black;
}

div.upload {
    background-color:#fff;
    border: 1px solid #ddd;
    border-radius:5px;
    display:inline-block;
    height: 30px;
    padding:3px 40px 3px 3px;
    position:relative;
    width: auto;
}

div.upload:hover {
    opacity:0.95;
}

div.upload input[type="file"] {
    display: input-block;
    width: 100%;
    height: 30px;
    opacity: 0;
    cursor:pointer;
    position:absolute;
    left:0;
}
.uploadButton {
    background-color: #425F9C;
    border: none;
    border-radius: 3px;
    color: #FFF;
    cursor:pointer;
    display: inline-block;
    height: 30px;
    margin-right:15px;
    width: auto;
    padding:0 20px;
    box-sizing: content-box;
}

.fileName {
    font-family: Arial;
    font-size:14px;
}

.upload + .uploadButton {
    height:38px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<form action="" method="post" enctype="multipart/form-data">
    <div class="upload">
        <input type="button" class="uploadButton" value="Browse" />
        <input type="file" name="upload" accept="image/*" id="fileUpload" />
        <span class="fileName">Select file..</span>
    </div>
    <input type="button" class="uploadButton" value="Upload File" />
</form>

Hope this helps!!!