[html] Styling an input type="file" button

How do you style an input type="file" button?

This question is related to html css file-io

The answer is


The best way is using the pseudo element :after or :before as an element overt the de input. Then style that pseudo element as you wish. I recomend you to do as a general style for all input files as follows:

input {
  height: 0px;
  outline: none;
}

input[type="file"]:before {
  content: "Browse";
  background: #fff;
  width: 100%;
  height: 35px;
  display: block;
  text-align: left;
  position: relative;
  margin: 0;
  margin: 0 5px;
  left: -6px;
  border: 1px solid #e0e0e0;
  top: -1px;
  line-height: 35px;
  color: #b6b6b6;
  padding-left: 5px;
  display: block;
}

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.


Here is a PURE CSS solution! It is Javascript-free! This one does not attempt to hide then recreate the original control, either, like the other posts here do. It uses plain CSS without any circus tricks to style the original file upload form control for all the major browsers.

This is what the file upload control looks like in Firefox, Chrome, and Edge using the CSS below. This is a very simple clean design. You can change it to look any way you like:

enter image description here

Internet Explorer gives you limited design control but at least you can manipulate the button using this CSS:

enter image description here

input[type="file"],
input[type="file"]:visited,
input[type="file"]:hover,
input[type="file"]:focus,
input[type="file"]:active {
    margin:0;
    padding: 0em 0em;
    padding: 0rem 0rem;
    overflow: hidden; /* long file names overflow so just hide the end */
    background: #ffffff;
    border-radius: .2em;
    border-radius: .2rem;
    outline: none;
    border: 2px solid #bbb;
    cursor: pointer;
    -webkit-appearance: textfield;
    -moz-appearance: textfield;
}

input[type="file"]:hover {
    background: #f9f9ff; /* I am using a light blue to indicate an interaction */
    border: 2px solid #999;
}

input[type="file"]:visited,
input[type="file"]:focus,
input[type="file"]:active {
    background: #fff; /* Default back to white when focused. */
    border: 2px solid #999;
}

/* Note: Firefox flags the file name box as a *readonly* input. So that attribute selector was added below. Note: These selectors blow up in IE so have to be separated from the same styles above. */
input[type="file"]:disabled,
input[type="file"]:read-only {
    margin: 0;
    padding: 0em 0em;
    padding: 0rem 0rem;
    overflow: hidden; /* long file names overflow so just hide the end */
    background: #ffffff;
    border-radius: .2em;
    border-radius: .2rem;
    outline: none;
    border: 2px solid #bbb;
    cursor: pointer;
    -webkit-appearance: textfield;
    -moz-appearance: textfield;
}

input[type="file"]:disabled:hover,
input[type="file"]:read-only:hover {
    background: #f9f9ff; /* I am using a light blue to indicate an interaction */
    border: 2px solid #999;
}

input[type="file"]:disabled:visited,
input[type="file"]:disabled:focus,
input[type="file"]:disabled:active,
input[type="file"]:read-only:visited,
input[type="file"]:read-only:focus,
input[type="file"]:read-only:active {
    background: #fff; /* Default back to white when focused. */
    border: 2px solid #999;
}

/* IE UPLOAD BUTTON STYLE: This attempts to alter the file upload button style in IE.  Keep in mind IE gives you limited design control but at least you can customize its upload button.*/
::-ms-browse { /* IE */
    display: inline-block;
    margin: 0;
    padding: .2em .5em;
    padding: .2rem .5rem;
    text-align: center;
    outline: none;
    border: none;
    background: #fff;
    white-space: nowrap;
    cursor: pointer;
}
/* FIREFOX UPLOAD BUTTON STYLE */
::file-selector-button {/* firefox */
    display: inline-block;
    margin: 0rem 1rem 0rem 0rem;
    padding: .18em .5em;
    padding: .18rem .5rem;
    -webkit-appearance: button;
    text-align: center;
    border-radius: .1rem 0rem 0rem .1rem;
    outline: none;
    border: none;
    border-right: 2px solid #bbb;
    background: #eee;
    white-space: nowrap;
    cursor: pointer;
}
/* CHROME AND EDGE UPLOAD BUTTON STYLE */
::-webkit-file-upload-button { /* chrome and edge */
    display: inline-block;
    margin: 0rem 1rem 0rem 0rem;
    padding: .19em .5em;
    padding: .19rem .5rem;
    -webkit-appearance: button;
    text-align: center;
    border-radius: .1rem 0rem 0rem .1rem;
    outline: none;
    border: none;
    border-right: 2px solid #bbb;
    background: #eee;
    white-space: nowrap;
    cursor: pointer;
}

Note: You might test it in older versions of Firefox, Chrome, Edge, and IE.


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


ONLY CSS

Use this very simple and EASY

_x000D_
_x000D_
.choose::-webkit-file-upload-button {_x000D_
  color: white;_x000D_
  display: inline-block;_x000D_
  background: #1CB6E0;_x000D_
  border: none;_x000D_
  padding: 7px 15px;_x000D_
  font-weight: 700;_x000D_
  border-radius: 3px;_x000D_
  white-space: nowrap;_x000D_
  cursor: pointer;_x000D_
  font-size: 10pt;_x000D_
}
_x000D_
<label>Attach your screenshort</label>_x000D_
<input type="file" multiple class="choose">
_x000D_
_x000D_
_x000D_


I found this approach the simplest and lightest.

Here is the working example: http://codepen.io/c3zar22/pen/QNoYXN

Below are the explanations:

  • this would be the markup:

    <label for="attach-project-file">
        <span id="remove-project-file" class="close">x</span>
        <div class="filename" id="attached-project-file">Click to select a file</div>
    </label>
    <input id="attach-project-file" type="file">
    
  • hide the input in a hacky way like this:

    #attach-project-file {
        width: 0.1px;
        height: 0.1px;
        opacity: 0;
        overflow: hidden;
        position: absolute;
        z-index: -1;
    }
    
  • style the corresponding label instead

    [for="attach-project-file"] {
        /* your styles here */
    }
    
  • style "remove file" button

    .close {
        font-size: 16px;
        padding: 10px;
        position: absolute;
        top: 0;
        right: 0;
        cursor: pointer;
        font-style: normal;
    }
    
  • .filename element will be used to display the selected file

  • below is the commented JS code needed (using jQuery) to make it work:

    var $attach = $('#attach-project-file'),
        $remove = $('#remove-project-file'),
        $name = $('#attached-project-file');
    
    // initially hide the remove button
    $remove.hide();
    
    // do this when file input has changed
    // i.e.: a file has been selected
    $attach.on('change', function() {
        var val = $(this).val();
        if (val !== '') {
            // if value different than empty
    
            // show the file name as text
            // hide/text/fadeIn creates a nice effect when changing the text
            $name
                .hide()
                .text(val)
                .fadeIn();
    
            // show the remove button
            $remove.fadeIn();
        } else {
            // if value empty, means the file has been removed
    
            // show the default text
            $name
                .hide()
                .text('Click to select a file')
                .fadeIn();
    
            // hide remove button
            $remove.fadeOut();
        }
    });
    
    // remove selected file when clicking the remove button
    // prevent click bubbling to the parent label and triggering file selection
    $remove.on('click', function(e) {
        e.preventDefault();
        e.stopPropagation();
    
        $attach
            .val('')
            .change(); // trigger change event
    });
    

Multiple file solution with converted filename

Bootstrap EXAMPLE

HTML:

<div>
  <label class="btn btn-primary search-file-btn">
    <input name="file1" type="file" style="display:None;"> <span>Choose file</span>
  </label>
  <span>No file selected</span>
</div>

<div>
  <label class="btn btn-primary search-file-btn">
    <input name="file2" type="file" style="display:None;"> <span>Choose file</span>
  </label>
  <span>No file selected</span>
</div>

1. JS with jQuery:

$().ready(function($){
    $('.search-file-btn').children("input").bind('change', function() {
    var fileName = '';
    fileName = $(this).val().split("\\").slice(-1)[0];
    $(this).parent().next("span").html(fileName);
  })
});

2. JS without jQuery

Array.prototype.forEach.call(document.getElementsByTagName('input'), function(item) {
  item.addEventListener("change", function() {
    var fileName = '';
    fileName = this.value.split("\\").slice(-1)[0];
    this.parentNode.nextElementSibling.innerHTML = fileName;
  });
});

Plug-in solutions I found were too heavy-weight, so, I made my own jQuery plug-in called Drolex FileStyle.

This plug-in allows you to style file input fields however you want. Actually, you style div elements to look like a tricked out file input, and the actual file input is automatically overlaid with 0% opacity. No additional HTML is required. Just include the css and js files in the page you want Drolex FileStyle and that's it! Edit the css file to your liking. Don't forget the jQuery library if your page doesn't already have it. If the client does not run JavaScript, then the file input will not be modified by js or css.

Tested to work in Chrome 24, Firefox 18, Internet Explorer 9. Expected to work in previous versions of those and others.

Download: http://web.drolex.net/Drolex-FileStyle.zip


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

_x000D_
_x000D_
.divs {_x000D_
    position: relative;_x000D_
    display: inline-block;_x000D_
    background-color: #fcc;_x000D_
}_x000D_
_x000D_
.inputs {_x000D_
    position:absolute;_x000D_
    left: 0px;_x000D_
    height: 100%;_x000D_
    width: 100%;_x000D_
    opacity: 0;_x000D_
    background: #00f;_x000D_
    z-index:999;_x000D_
}_x000D_
_x000D_
.icons {_x000D_
    position:relative;_x000D_
}
_x000D_
<div class="divs">_x000D_
<input type='file' id='image' class="inputs">_x000D_
<i class="fa fa-image fa-2x icons"></i>_x000D_
</div>_x000D_
_x000D_
<div class="divs">_x000D_
<input type='file' id='book' class="inputs">_x000D_
<i class="fa fa-book fa-5x icons"></i>_x000D_
</div>_x000D_
<br><br><br>_x000D_
<div class="divs">_x000D_
<input type='file' id='data' class="inputs">_x000D_
<i class="fa fa-id-card fa-3x icons"></i>_x000D_
</div>_x000D_
_x000D_
_x000D_
_x000D_
_x000D_
_x000D_
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
_x000D_
_x000D_
_x000D_

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.


Here's a cross compatible method which will work in Chrome, Firefox, Safari, and IE.

_x000D_
_x000D_
$(window).on('resize',function() {_x000D_
 var eqw = $('input[type=text]').width();_x000D_
 $('textarea').width(eqw - 32);_x000D_
 $('.fileoutline').width(eqw);_x000D_
}).trigger('resize');_x000D_
_x000D_
$('.file+.file').hide();_x000D_
_x000D_
$(".file").click(function() {_x000D_
    var input = $(this).next().find('input');_x000D_
    input.click();_x000D_
});_x000D_
$("input[id='file1']").change(function () {_x000D_
 $('.file+.file').show();_x000D_
 var filename = $(this).val();_x000D_
 $('.filename1').html(filename);_x000D_
 $('.file').find('span').html('CHANGE FILE');_x000D_
});_x000D_
$("input[id='file2']").change(function() {_x000D_
 var filename = $(this).val();_x000D_
 $('.filename2').html(filename);_x000D_
 $('.file').find('span').html('CHANGE FILE');_x000D_
});_x000D_
 
_x000D_
form { width:55%;margin:0 auto;padding-left:3vw;text-align:left; }_x000D_
fieldset{border:0;margin:0;padding:0;}_x000D_
textarea{overflow: auto;height:25vh;resize:none;outline:none;width:93%;background:none;padding:8px 15px;display:block;text-align:left;border:1px solid #000;margin:0;color:#000;font:700 0.85em/2.2 'Futura Book',Arial,sans-serif;}_x000D_
input:focus{outline:none;}_x000D_
input[type=text]{font-weight:700;font-size:0.85em;line-height:2.2;background:none;text-align:left;letter-spacing:0.02em;height:33px;display:block;width:100%;border:none;border-bottom:1px solid #000;margin:0 0 28px;color:#000;}_x000D_
input:focus{outline:0;}_x000D_
.fileoutline { width:100%;margin:25px auto 0px;left:0;right:0;height:40px;border:1px solid #000;position:relative; }_x000D_
input[type=file] { -webkit-appearance: none;-moz-appearance:none;appearance: none;opacity:0;position:relative;width:100%;height:35px;font-weight:700;font-size:0.5em;line-height:28px;letter-spacing:0.2em;position: absolute;left: 0;top: 0;height: 100%;z-index:10; }_x000D_
.file,.filename1,.filename2,#submit { font-size:10px;letter-spacing:0.02em;text-transform:uppercase;color:#ffffff;text-align:center;width:35%;}_x000D_
.file,.filename1,.filename2 { font-weight:200;line-height:28px;}_x000D_
.filename1,.filename2 { width:375px;overflow:hidden;top:0;text-align:right;position:absolute;display:block;height:26px;color:#000;}_x000D_
.file { position:absolute;width:100px;top:6px;left:10px;background:#000;border-radius:14px; }_x000D_
::-webkit-file-upload-button,::-ms-browse { width: 100%;height:25px;opacity: 0;-webkit-appearance: none;appearance: none; }_x000D_
#submit{border:none;height:32px;background: #000;box-shadow:0 0 0 0.5px #fff,0 0 0 5px #000;margin:35px 0;float:right;display:block;}
_x000D_
<form action="" method="post" enctype="multipart/form-data">_x000D_
    <input type="text" name="email" id="email" placeholder="Email address" />_x000D_
    <input type="text"  type="text" name="name" id="title" placeholder="Name" />_x000D_
    <textarea rows="7" cols="40" name="description" id="description" placeholder="Description"></textarea>_x000D_
    <div class="fileoutline"><div class="file"><span>CHOOSE FILE</span><input type="file" name="file[]" id="file1"><div class="filename1">NO CHOSEN FILE</div></div></div>_x000D_
    <div class="fileoutline"><div class="file"><span>CHOOSE FILE</span><input type="file" name="file[]" id="file2"><div class="filename2">NO CHOSEN FILE</div></div></div>_x000D_
    <input type="submit" name="submit" value="Submit" id="submit">_x000D_
</form>
_x000D_
_x000D_
_x000D_


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 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.

_x000D_
_x000D_
.attachFileSpan{_x000D_
color:#2b6dad;_x000D_
cursor:pointer;_x000D_
}_x000D_
.attachFileSpan:hover{_x000D_
text-decoration: underline;_x000D_
}
_x000D_
<h3> Customized input of type file </h3>_x000D_
<input id="myInput" type="file" style="visibility:hidden"/>_x000D_
_x000D_
        <span title="attach file" class="attachFileSpan" onclick="document.getElementById('myInput').click()">_x000D_
        Attach file_x000D_
        </span>
_x000D_
_x000D_
_x000D_

Reference


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.


Put upload file button over your nice button or element and hide it.

Very simple and will work on any browser

<div class="upload-wrap">
    <button type="button" class="nice-button">upload_file</button>
    <input type="file" name="file" class="upload-btn">
</div>

Styles

.upload-wrap {
    position: relative;
}

.upload-btn {
    position: absolute;
    left: 0;
    opacity: 0;
}

This is a nice way to do it with material / angular file upload. You could do the same with a bootstrap button.

Note I used <a> instead of <button> this allows the click events to bubble up.

<label>
    <input type="file" (change)="setFile($event)" style="display:none" />

    <a mat-raised-button color="primary">
      <mat-icon>file_upload</mat-icon>
      Upload Document
    </a>

  </label>

The best way I have found is having an input type: file then setting it to display: none. Give it an id. Create a button or any other element you want to open the file input.

Then add an event listener on it (button) which when clicked simulates a click on the original file input. Like clicking a button named hello but it opens a file window.

Example code

//i am using semantic ui

<button class="ui circular icon button purple send-button" id="send-btn">
      <i class="paper plane icon"></i>
    </button>
  <input type="file" id="file" class="input-file" />

javascript

var attachButton=document.querySelector('.attach-button');
    attachButton.addEventListener('click', e=>{
        $('#file').trigger("click")
    })

A quick and crude way is to set the label as a button and set position to absolute so it floats over original button, you still see file name. I am thinking about a mobile solution however.


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

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

_x000D_
_x000D_
.btn-file {_x000D_
  position: relative;_x000D_
  overflow: hidden;_x000D_
}_x000D_
.btn-file input[type=file] {_x000D_
  position: absolute;_x000D_
  top: 0;_x000D_
  right: 0;_x000D_
  min-width: 100%;_x000D_
  min-height: 100%;_x000D_
  font-size: 100px;_x000D_
  text-align: right;_x000D_
  filter: alpha(opacity=0);_x000D_
  opacity: 0;_x000D_
  outline: none;_x000D_
  background: white;_x000D_
  cursor: inherit;_x000D_
  display: block;_x000D_
}
_x000D_
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />_x000D_
_x000D_
<span class="btn btn-primary btn-file">_x000D_
    Browse...<input type="file">_x000D_
</span>
_x000D_
_x000D_
_x000D_

Which produces the following file input button:

Example button

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


This week I also needed to custom the button and display the selected file name aside it, so after reading some of the answers above (Thanks BTW) I came up with the following implementation:

HTML:

<div class="browse">
<label id="uploadBtn" class="custom-file-upload">Choose file
<input type="file" name="fileInput" id="fileInput" accept=".yaml" ngf-select ngf-change="onFileSelect($files)" />
</label>
<span>{{fileName}}</span>
</div>

CSS

   input[type='file'] {
    color: #a1bbd5;
    display: none;

}

.custom-file-upload {
    border: 1px solid #a1bbd5;
    display: inline-block;
    padding: 2px 8px;
    cursor: pointer;
}

label{
    color: #a1bbd5;
    border-radius: 3px;
}

Javascript (Angular)

app.controller('MainCtrl', function($scope) {

        $scope.fileName = 'No file chosen';

          $scope.onFileSelect = function ($files) {
          $scope.selectedFile = $files;
          $scope.fileName = $files[0].name;
    };
});

Basically I'm working with ng-file-upload lib, Angular-wise I'm binding the filename to my $scope and giving it the initial value of 'No file chosen', I'm also binding the onFileSelect() function to my scope so when a file gets selected I'm getting the filename using ng-upload API and assign it to the $scope.filename.


<input type="file" name="media" style="display-none" onchange="document.media.submit()">

I would normally use simple javascript to customize the file input tag.A hidden input field,on click of button,javascript call the hidden field,simple solution with out any css or bunch of jquery.

<button id="file" onclick="$('#file').click()">Upload File</button>

I am able to do it with pure CSS using below code. I have used bootstrap and font-awesome.

_x000D_
_x000D_
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />_x000D_
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" rel="stylesheet" />_x000D_
_x000D_
<label class="btn btn-default btn-sm center-block btn-file">_x000D_
  <i class="fa fa-upload fa-2x" aria-hidden="true"></i>_x000D_
  <input type="file" style="display: none;">_x000D_
</label>
_x000D_
_x000D_
_x000D_


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:

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

This displays as follows in IE10 on Windows 8:

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:

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

This displays as follows in Chrome 26 on OS X:

This displays as follows in Chrome 26 on OS X:


Simply simulate a click on the <input> by using the trigger() function when clicking on a styled <div>. I created my own button out of a <div> and then triggered a click on the input when clicking my <div>. This allows you to create your button however you want because it's a <div> and simulates a click on your file <input>. Then use display: none on your <input>.

// div styled as my load file button
<div id="simClick">Load from backup</div>

<input type="file" id="readFile" />

// Click function for input
$("#readFile").click(function() {
    readFile();
});

// Simulate click on the input when clicking div
$("#simClick").click(function() {
    $("#readFile").trigger("click");
});

css can do a lot here... with a little trickery...

<div id='wrapper'>
  <input type='file' id='browse'>
</div>

#wrapper {
     width: 93px; /*play with this value */
     height: 28px; /*play with this value */
     background: url('browseBtn.png') 0 0 no-repeat;
     border:none;
     overflow:hidden;
}

#browse{
     margin-left:-145px; /*play with this value */
     opacity:0; /* set to .5 or something so you can better position it as an overlay then back to zero again after you're done */
     -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
     filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
}

::reference::http://site-o-matic.net/?viewpost=19

-abbey


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


Here's a simple css only solution, that creates a consistent target area, and lets you style your faux elements however you like.

The basic idea is this:

  1. Have two "fake" elements (a text input/link) as siblings to your real file input. Absolutely position them so they're exactly on top of your target area.
  2. Wrap your file input with a div. Set overflow to hidden (so the file input doesn't spill out), and make it exactly the size that you want your target area to be.
  3. Set opacity to 0 on the file input so it's hidden but still clickable. Give it a large font size so the you can click on all portions of the target area.

Here's the jsfiddle: http://jsfiddle.net/gwwar/nFLKU/

<form>
    <input id="faux" type="text" placeholder="Upload a file from your computer" />
    <a href="#" id="browse">Browse </a>
    <div id="wrapper">
        <input id="input" size="100" type="file" />
    </div>
</form>

If anyone still cares on how to do this without JavaScript, let me complete Josh answer:

How to display the text of the filename:

The easiest way is to set both elements to a position:relative, give the label a higher z-index and give the input file negative margin until the label text is where you want it to be. Do not use display:none on the input!

Example:

input[type="file"] {
  position:relative;
  z-index:1;
  margin-left:-90px;
}

.custom-file-upload {
  border: 1px solid #ccc;
  display: inline-block;
  padding: 6px 12px;
  cursor: pointer;
  position:relative;
  z-index:2;
  background:white;

}

follow these steps then you can create custom styles for your file upload form:

  1. this is the simple HTML form(please read the HTML comments I have written here below)

    <form action="#type your action here" method="POST" enctype="multipart/form-data">
      <div id="yourBtn" style="height: 50px; width: 100px;border: 1px dashed #BBB; cursor:pointer;" onclick="getFile()">Click to upload!</div>
      <!-- this is your file input tag, so i hide it!-->
      <div style='height: 0px;width:0px; overflow:hidden;'><input id="upfile" type="file" value="upload"/></div>
      <!-- here you can have file submit button or you can write a simple script to upload the file automatically-->
      <input type="submit" value='submit' >
    </form>
    
  2. then use this simple script to pass the click event to file input tag.

    function getFile(){
         document.getElementById("upfile").click();
    }
    

    Now you can use any type of styling without worrying about how to change default styles.

I know this very well because I have been trying to change the default styles for a month and a half. believe me, it's very hard because different browsers have different upload input tag. So use this one to build your custom file upload forms. Here is the full AUTOMATED UPLOAD code.

_x000D_
_x000D_
function getFile() {_x000D_
  document.getElementById("upfile").click();_x000D_
}_x000D_
_x000D_
function sub(obj) {_x000D_
  var file = obj.value;_x000D_
  var fileName = file.split("\\");_x000D_
  document.getElementById("yourBtn").innerHTML = fileName[fileName.length - 1];_x000D_
  document.myForm.submit();_x000D_
  event.preventDefault();_x000D_
}
_x000D_
#yourBtn {_x000D_
  position: relative;_x000D_
  top: 150px;_x000D_
  font-family: calibri;_x000D_
  width: 150px;_x000D_
  padding: 10px;_x000D_
  -webkit-border-radius: 5px;_x000D_
  -moz-border-radius: 5px;_x000D_
  border: 1px dashed #BBB;_x000D_
  text-align: center;_x000D_
  background-color: #DDD;_x000D_
  cursor: pointer;_x000D_
}
_x000D_
<form action="#type your action here" method="POST" enctype="multipart/form-data" name="myForm">_x000D_
  <div id="yourBtn" onclick="getFile()">click to upload a file</div>_x000D_
  <!-- this is your file input tag, so i hide it!-->_x000D_
  <!-- i used the onchange event to fire the form submission-->_x000D_
  <div style='height: 0px;width: 0px; overflow:hidden;'><input id="upfile" type="file" value="upload" onchange="sub(this)" /></div>_x000D_
  <!-- here you can have file submit button or you can write a simple script to upload the file automatically-->_x000D_
  <!-- <input type="submit" value='submit' > -->_x000D_
</form>
_x000D_
_x000D_
_x000D_


This approach gives you the whole flexibility! ES6 / VanillaJS!

html:

<input type="file" style="display:none;"></input>
<button>Upload file</button>

javascript:

document.querySelector('button').addEventListener('click', () => {
  document.querySelector('input[type="file"]').click();
});

This hides the input-file button, but under the hood clicks it from another normal button, that you can obviously style like any other button. This is the only solution with no downside apart from a useless DOM-node. Thanks to display:none;, the input-button does not reserve any visible space in the DOM.

(I don't know anymore to whom to give props for this. But I got that idea from somewhere here on Stackoverflow.)


jquery version of teshguru script for automatically detect input[file] and style

<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<style>
#yourBtn{
   position: relative;
       top: 150px;
   font-family: calibri;
   width: 150px;
   padding: 10px;
   -webkit-border-radius: 5px;
   -moz-border-radius: 5px;
   border: 1px dashed #BBB; 
   text-align: center;
   background-color: #DDD;
   cursor:pointer;
  }
</style>
<script type="text/javascript">
$(document).ready(function()
{
    $('input[type=file]').each(function()
    {
        $(this).attr('onchange',"sub(this)");
        $('<div id="yourBtn" onclick="getFile()">click to upload a file</div>').insertBefore(this);
        $(this).wrapAll('<div style="height: 0px;width: 0px; overflow:hidden;"></div>');
    });
});
 function getFile(){
   $('input[type=file]').click();
 }
 function sub(obj){
    var file = obj.value;
    var fileName = file.split("\\");
    document.getElementById("yourBtn").innerHTML = fileName[fileName.length-1];
 }
</script>
</head>
<body>
<?php 
    var_dump($_FILES);
?>
<center>
<form action="" method="post" enctype="multipart/form-data" name="myForm">

<input id="upfile" name="file" type="file" value="upload"/>
<input type="submit" value='submit' >
</form>
</center>
</body>
</html>

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 Stack Overflow, 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/

_x000D_
_x000D_
$('input[type=file]').change(function(e) {_x000D_
    $in = $(this);_x000D_
    $in.next().html($in.val());_x000D_
    _x000D_
});_x000D_
_x000D_
$('.uploadButton').click(function() {_x000D_
    var fileName = $("#fileUpload").val();_x000D_
    if (fileName) {_x000D_
        alert(fileName + " can be uploaded.");_x000D_
    }_x000D_
    else {_x000D_
        alert("Please select a file to upload");_x000D_
    }_x000D_
});
_x000D_
body {_x000D_
    background-color:Black;_x000D_
}_x000D_
_x000D_
div.upload {_x000D_
    background-color:#fff;_x000D_
    border: 1px solid #ddd;_x000D_
    border-radius:5px;_x000D_
    display:inline-block;_x000D_
    height: 30px;_x000D_
    padding:3px 40px 3px 3px;_x000D_
    position:relative;_x000D_
    width: auto;_x000D_
}_x000D_
_x000D_
div.upload:hover {_x000D_
    opacity:0.95;_x000D_
}_x000D_
_x000D_
div.upload input[type="file"] {_x000D_
    display: input-block;_x000D_
    width: 100%;_x000D_
    height: 30px;_x000D_
    opacity: 0;_x000D_
    cursor:pointer;_x000D_
    position:absolute;_x000D_
    left:0;_x000D_
}_x000D_
.uploadButton {_x000D_
    background-color: #425F9C;_x000D_
    border: none;_x000D_
    border-radius: 3px;_x000D_
    color: #FFF;_x000D_
    cursor:pointer;_x000D_
    display: inline-block;_x000D_
    height: 30px;_x000D_
    margin-right:15px;_x000D_
    width: auto;_x000D_
    padding:0 20px;_x000D_
    box-sizing: content-box;_x000D_
}_x000D_
_x000D_
.fileName {_x000D_
    font-family: Arial;_x000D_
    font-size:14px;_x000D_
}_x000D_
_x000D_
.upload + .uploadButton {_x000D_
    height:38px;_x000D_
}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>_x000D_
<form action="" method="post" enctype="multipart/form-data">_x000D_
    <div class="upload">_x000D_
        <input type="button" class="uploadButton" value="Browse" />_x000D_
        <input type="file" name="upload" accept="image/*" id="fileUpload" />_x000D_
        <span class="fileName">Select file..</span>_x000D_
    </div>_x000D_
    <input type="button" class="uploadButton" value="Upload File" />_x000D_
</form>
_x000D_
_x000D_
_x000D_

Hope this helps!!!


Working example here with native Drag and drop support : https://jsfiddle.net/j40xvkb3/

When styling a file input, you shouldn't break any of native interaction the input provides.

The display: none approach breaks the native drag and drop support.

To not break anything, you should use the opacity: 0 approach for the input, and position it using relative / absolute pattern in a wrapper.

Using this technique, you can easily style a click / drop zone for the user, and add custom class in javascript on dragenter event to update styles and give user a feedback to let him see that he can drop a file.

HTML :

<label for="test">
  <div>Click or drop something here</div>
  <input type="file" id="test">
</label>

CSS :

input[type="file"] {
  position: absolute;
  left: 0;
  opacity: 0;
  top: 0;
  bottom: 0;
  width: 100%;
}

div {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #ccc;
  border: 3px dotted #bebebe;
  border-radius: 10px;
}

label {
  display: inline-block;
  position: relative;
  height: 100px;
  width: 400px;
}

Here is a working example (with additional JS to handle dragover event and dropped files).

https://jsfiddle.net/j40xvkb3/

Hope this helped !


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;
}

 <label>
    <input type="file" />
 </label>

You can wrap your input type="file" inside of a label for the input. Style the label however you'd like and hide the input with display: none;


VISIBILITY:hidden TRICK

I usually go for the visibility:hidden trick

this is my styled button

<div id="uploadbutton" class="btn btn-success btn-block">Upload</div>

this is the input type=file button. Note the visibility:hidden rule

<input type="file" id="upload" style="visibility:hidden;">

this is the JavaScript bit to glue them together. It works

<script>
 $('#uploadbutton').click(function(){
    $('input[type=file]').click();
 });
 </script>

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; }

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.


_x000D_
_x000D_
$('.new_Btn').click(function() {
  $('#html_btn').click();
});
_x000D_
.new_Btn {
  // your css propterties
}

#html_btn {
  display: none;
}
_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="new_Btn">SelectPicture</div><br>
<input id="html_btn" type='file' " /><br>
_x000D_
_x000D_
_x000D_

You can reach your goals too without jQuery with normal JavaScript.

Now the newBtn is linkes with the html_btn and you can style your new btn like you want :D


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;
    });
});

As JGuo and CorySimmons mentioned, you can use the clickable behaviour of a stylable label, hiding the less flexible file input element.

<!DOCTYPE html>
<html>
<head>
<title>Custom file input</title>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
</head>

<body>

<label for="upload-file" class="btn btn-info"> Choose file... </label>
<input id="upload-file" type="file" style="display: none"
onchange="this.nextElementSibling.textContent = this.previousElementSibling.title = this.files[0].name">
<div></div>

</body>
</html>

In case you're looking for a javascript library - out of the box solution, jquery-fileinput works fine.


Examples related to html

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment

Examples related to css

need to add a class to an element Using Lato fonts in my css (@font-face) Please help me convert this script to a simple image slider Why there is this "clear" class before footer? How to set width of mat-table column in angular? Center content vertically on Vuetify bootstrap 4 file input doesn't show the file name Bootstrap 4: responsive sidebar menu to top navbar Stylesheet not loaded because of MIME-type Force flex item to span full row width

Examples related to file-io

Python, Pandas : write content of DataFrame into text File Saving response from Requests to file How to while loop until the end of a file in Python without checking for empty line? Getting "java.nio.file.AccessDeniedException" when trying to write to a folder How do I add a resources folder to my Java project in Eclipse Read and write a String from text file Python Pandas: How to read only first n rows of CSV files in? Open files in 'rt' and 'wt' modes How to write to a file without overwriting current contents? Write objects into file with Node.js