Shivanand
Shivanand

Reputation: 11899

Styling an input type="file" button

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

<input type="file" />

Upvotes: 1137

Views: 1972162

Answers (30)

Mohammed almalki
Mohammed almalki

Reputation: 693

With this code

, I could control the text with the input and the input button.

input[type="file"]::file-selector-button{ /* the button to select file */
    background-color: #ffffff;
    margin: 0;
    padding: 0.5rem;
    border: 0;
    border-color: #000000;
    border-right-width: 1px;
    border-style: solid;
    color: rgb(0, 0, 0);
    height: 100%;
}
input[type="file"]::file-selector-button:hover{
    background-color: #a7a7a7;
}

input[type="file"]::file-selector-button:active{
    background-color: #ffffff;
}

input[type="file" i]{ /* the name of the selected file */
    width: 100%;
}

.image_input_container{
    background-color: #ffffff;
    display:flex;
    margin: 0.5rem;
    padding: 0;
    border: 0;
    border-color: #000000;
    border-width: 1px;
    border-style: solid;
    max-width: 100%;
    color: rgb(0, 0, 0);
}
<label class="image_input_container"><input type="file" name="image"></label>

Upvotes: 2

Josh Crozier
Josh Crozier

Reputation: 240928

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

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

.custom-file-upload {
  border: 1px solid #ccc;
  display: inline-block;
  padding: 6px 12px;
  cursor: pointer;
}
<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;
}

Working example:

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.

Upvotes: 1627

ADAMJR
ADAMJR

Reputation: 2738

::file-selector-button

https://developer.mozilla.org/en-US/docs/Web/CSS/::file-selector-button

This is a new selector that can be used to style the file selector button.

It has full support on recent browser versions.

input[type=file]::file-selector-button {
  border: 2px solid #6c5ce7;
  padding: .2em .4em;
  border-radius: .2em;
  background-color: #a29bfe;
  transition: 1s;
}

input[type=file]::file-selector-button:hover {
  background-color: #81ecec;
  border: 2px solid #00cec9;
}
<form>
  <label for="fileUpload">Upload file</label>
  <input type="file" id="fileUpload">
</form>

Here is another snippet that demonstrates different styling:

.input_container {
  border: 1px solid #e5e5e5;
}

input[type=file]::file-selector-button {
  background-color: #fff;
  color: #000;
  border: 0px;
  border-right: 1px solid #e5e5e5;
  padding: 10px 15px;
  margin-right: 20px;
  transition: .5s;
}

input[type=file]::file-selector-button:hover {
  background-color: #eee;
  border: 0px;
  border-right: 1px solid #e5e5e5;
}
<form>
  <div class="input_container">
    <input type="file" id="fileUpload">
  </div>
</form>

I felt that this answer was needed as most answers here are outdated.


Customize Input Text

If you want to customize the text of the file selector button, here is a snippet:

document.querySelector("#files").onchange = function() {
  const fileName = this.files[0]?.name;
  const label = document.querySelector("label[for=files]");
  label.innerText = fileName ?? "Browse Files";
};
label {
  border: 1px solid #e5e5e5;
  border-radius: 10px;
  padding: 5px 10px;
  font-family: 'Helvetica', sans-serif;
  transition: .5s;
}

label:hover {
  background-color: #eee;
}
<div class="input_container">
  <label for="files" class="btn">Browse Files</label>
  <input id="files" style="display:none;" type="file">
</div>

I preferred to use a vanilla solution for simplicity. View this post if you want a jQuery version of the above snippet.

Upvotes: 202

Rich - enzedonline
Rich - enzedonline

Reputation: 1258

The more recent suggestions to use both [type="file"] and [type="file"]::file-selector-button were great tips, but the solutions target every file input in the site rather than just the element in hand.

To hide the chosen text (this is what I was looking for), the only attribute that needs adjusting is the width on the input and the button (they should match).

To target just a subset of file inputs, set a custom class on the <input> element (e.g. class="custom-fileinput") then use this in your selector constructs.

For my need, to hide the chosen file text, I ended up with the following css:

.custom-fileinput, .custom-fileinput::file-selector-button {
    width: 12em;
}

Upvotes: 0

Joel Stransky
Joel Stransky

Reputation: 440

There are a lot of solutions here but I wanted to add something with modern considerations in mind. No hidden or visibility hacks. JS will still be needed to enhance with feedback and drag & drop.

The key is in setting the button to 100% width;

[type="file"]::file-selector-button {
  width: 100%;
}

[type="file"] {
  width: 50%;
  min-width: 14ch;
}

[type="file"]::file-selector-button {
  width: 100%;
  margin-inline-end: 0;
  padding: 0.6rem;
  background-color: lightblue;
  color: smoke;
  border: none;
  border-radius: 0;
  text-transform: uppercase;
}
<input type="file" />

Upvotes: 1

Stokely
Stokely

Reputation: 15819

Here is a PURE CSS, Javascript-free, Bootstrap-free, 100% cross-browser solution! Just cut-and-paste one block of styles, then test your file upload control.

This solution does NOT attempt to hide then recreate the original HTML element like the other posts here do. It uses plain CSS without any circus tricks or third party tools to style the original file upload form control for all the major browsers. You do not need to even change your HTML code! Just cut-and-paste the code below into your web page to test it...

<style>
/* Note: This CSS will style all instances of 
   <input type=file /> controls in your website. */
input[type="file"],
input[type="file"]:visited,
input[type="file"]:hover,
input[type="file"]:focus,
input[type="file"]:active {
    margin:0;
    padding: 0em 0em;/* fallback: older browsers like IE 1-8 need "em" */
    padding: 0rem 0rem;/* older browsers dont know what "rem" is */
    overflow: hidden; /* long file names overflow so just hide the end */
    background: #fff;
    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; /* Optional rollover color: 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: These "disabled" selectors blow up in IE so have to be separated from the same styles above. */
input[type="file"]:disabled {
    margin: 0;
    padding: 0em 0em;
    padding: 0rem 0rem;
    overflow: hidden; /* long file names overflow so just hide the end */
    background: #ddd;
    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 {
    background: #ddd; /* disabled-readonly buttons should be grey */
    border: 2px solid #999;
}

input[type="file"]:disabled:visited,
input[type="file"]:disabled:focus,
input[type="file"]:disabled:active {
    background: #ddd; /* disabled-readonly buttons should be grey */
    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;
}
</style>

<input type="file" id="fileupload" name="fileupload" 
value="" tabindex="0" enctype="multipart/form-data" 
accept="image/*" autocomplete="off" multiple="multiple" 
aria-multiselectable="true" title="Multiple File Upload" 
aria-label="Multiple File Upload" />

<br /><br />

<input disabled="disabled" type="file" id="fileupload" 
name="fileupload" value="" tabindex="0" 
enctype="multipart/form-data" accept="image/*" 
autocomplete="off" multiple="multiple" 
aria-multiselectable="true" title="Disabled Multiple File Upload" 
aria-label="Disabled Multiple File Upload" />

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 control using CSS enough to change a few things, including rounded borders and colors:

enter image description here

The advantages to my solution are:

  1. You stick with simple CSS to style the original HTML input control
  2. You can see one or more file names in the file input textbox
  3. Screen readers and ARIA-friendly devices can interact normally with your file upload control
  4. You can set tabindex on your HTML element so its part of the tab order
  5. Because you are using plain HTML and CSS, your file input button works perfectly in old and new browsers
  6. ZERO JavaScript required!
  7. Runs and loads lighting fast in even the oldest of browsers
  8. Because your are not using "display:none" to hide the control, its file block stream data is never disabled from reaching the server in any old or new browser version known

You do not need goofy JavaScript tricks, Bootstrap, or to try and hide/recreate your file input control. That just destroys usability for everyone online. Styling the original HTML control means your file upload control is guaranteed to work well in 25 years worth of web browsers, old and new.

This is why you cannot trust all these scripted hacks here that erase, rewrite, or destroy HTML just to try and recreate some visual experience. That shows that you do not understand how HTML is used or why its been around for 30 years practically unchanged. You should never try and rewrite HTML's native form control functionality. Why? There is more to using natural HTML in websites than just manipulation of markup for some forced visual experience. The trade-offs of limited visual design in these replaced HTML elements was designed that way for a reason.

My advice: Stay with simple HTML and CSS solutions and you will have ZERO problems as a web developer.

Upvotes: 13

Wykk
Wykk

Reputation: 822

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

#html_btn {
  display: none;
}
<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>

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

Upvotes: 74

RixTheTyrunt
RixTheTyrunt

Reputation: 406

You can make an awesome ( unfinished ) File Uploader to a <button> element or any other element:

function selectFile() {
    document.getElementById("fileSelector").click();
}
input#fileSelector[type="file"] {
    display: none;
}

button[onclick*="()"] {
    cursor: pointer;
}
<input type="file" id="fileSelector">
<button onclick="selectFile()">Select file from computer...</button>

Upvotes: 1

Weilory
Weilory

Reputation: 3111

A demo for image upload application suitable for most of the backend with nice animation features.

// common
function render_element(styles, el) {
    for (const [kk, vv] of Object.entries(styles)) {
        el.style[kk] = vv;
    }
}

function hoverOpacity(el) {
    el.addEventListener('mouseenter', function() {
        el.style.opacity = 0.75
    }.bind(el));
    el.addEventListener('mouseleave', function() {
        el.style.opacity = 1
    }.bind(el));
}

// return void event handler on setTimeout
function buffer(func, time){
    return e=>{
        if(func.still)return;
        // first runtime
        if(!func.pft){
            func(e);
            func.pft = true;
            func.still = false;
            return;
        }
        func.still = true;
        setTimeout(e=>{
            func(e);
            func.still = false;
        }, time);
    }
}
// end of common

const imageUploadButton = document.getElementById('image-upload-button');
imageUploadButton.addEventListener('click', e=>{
    // pulse animation total time
    const d1 = document.getElementById('image-form');
    let time = 600;

    if(d1.rendered){
        d1.ready();
    }else{
        d1.ready = function(){
            d1.style.display = 'flex';
            d1.style.background = '#c5edd0';
            this.d2.style.background = '#b4dbbf';
            this.d3.style.background = '#95dea9';
            this.d4.innerHTML = 'Drag and Drop or Click Above to Upload';
        }
        let dismiss_btn = document.createElement('div');
        render_element({
            position: 'absolute',
            height: '30px',
            width: '30px',
            top: '0', 
            right: '0',
            background: '#fff',
            borderRadius: '30px',
            cursor: 'pointer', 
            margin: '2px',
            zIndex: '10',
        }, dismiss_btn);
        dismiss_btn.addEventListener('mouseenter', function(){this.style.background = '#fc4f30'});
        dismiss_btn.addEventListener('mouseleave', function(){this.style.background = '#fff'});
        dismiss_btn.addEventListener('click', ()=>{d1.style.display = 'none'});
        d1.appendChild(dismiss_btn);
        const d3 = d1.querySelector('#image-input');
        const d5 = d1.querySelector('#image-submit');
        d5.style.visibility = 'hidden';
        d1.parentNode.removeChild(d1);
        document.body.appendChild(d1);
        d1.removeChild(d3);
        let [
            d2, 
            d4, 
        ] = Array.from({length: 3}, ()=>document.createElement('div'));
        let width = window.innerWidth;
        let d_styles = {
            display: 'flex',
            justifyContent: 'center', 
            alignItems: 'center',
        };
        render_element({
            position: 'fixed',
            left: ((width - 430) / 2).toString() + 'px', 
            width: '430px',
            top: '60px',
            height: '280px',
            zIndex: '10', 
        }, d1);
        render_element(d_styles, d1);

        render_element({
            width: '90%',
            height: '90%', 
        }, d2);
        render_element(d_styles, d2);

        render_element({
            width: '80%',
            height: '70%', 
            fontSize: '0',
            cursor: 'pointer',
        }, d3);
        hoverOpacity(d3);
        render_element(d_styles, d3);

        d1.appendChild(d2);
        d2.appendChild(d3);

        let tt = time / 3;
        let ht = tt / 2;
        d1.addEventListener('dragover', buffer(e=>{
            d1.style.background = '#ebf9f0';
            setTimeout(()=>{
                d1.style.background = '#95dea9';
            }, ht);
            setTimeout(()=>{
                d2.style.background = '#b6e3c2';
                setTimeout(()=>{
                    d2.style.background = '#c4eed2';
                }, ht);
            }, tt);
            setTimeout(()=>{
                d3.style.background = '#cae3d1';
                setTimeout(()=>{
                    d3.style.background = '#9ce2b4';
                }, ht);
            }, tt);
        }, time));

        d2.style.flexDirection = 'column';
        render_element({
            fontSize: '16px',
            textAlign: 'center',
            fontFamily: 'Verdana',
        }, d4);
        d2.appendChild(d4);

        d3.addEventListener('change', e=>{
            // backend
            // d5.click();
            // if backend succeed, run frontend
            setTimeout(()=>{
                d1.style.background = '#dbcea2';
                setTimeout(()=>{
                    d2.style.background = '#dbc169';
                    setTimeout(()=>{
                        d3.style.background = '#ebc034';
                    }, ht);
                }, tt);
            }, time);
            // display backend path here
            // now only display filename
            d4.innerHTML = d3.files[0].name;
        });
        d1.d2 = d2;
        d1.d3 = d3;
        d1.d4 = d4;
        d1.ready();
        d1.rendered = true;
    }
});
#image-upload-button{
    width: 200px;
    height: 40px;
    background: lightgrey;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

#image-form{
    display: none;
}

::-webkit-file-upload-button {
    visibility: hidden;
}
<div id="image-upload-button">Upload Image
    <form id="image-form" action="post">
        <input id="image-input" type="file" />
        <button id="image-submit" type="submit"></button>
    </form>
</div>

Upvotes: 2

JDawg
JDawg

Reputation: 9500

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

See https://www.abeautifulsite.net/posts/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:

Example button

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

Upvotes: 44

TLK
TLK

Reputation: 1770

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.

Upvotes: 13

corysimmons
corysimmons

Reputation: 7675

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">
<style>
    .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;
    }
</style>

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)

Upvotes: 4

Abbey
Abbey

Reputation: 218

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

<div id='wrapper'>
    <input type='file' id='browse'>
</div>
<style>
    #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);
    }
</style>

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

-abbey

Upvotes: 2

Michel
Michel

Reputation: 4157

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>
<script>
    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';
    }
</script>
<style>
    .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;
    }
</style>

Upvotes: 0

codepleb
codepleb

Reputation: 10571

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

Upvotes: 19

Balvant Ahir
Balvant Ahir

Reputation: 620

ONLY CSS

Use this very simple and EASY

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

Upvotes: 27

ChrisRob
ChrisRob

Reputation: 1552

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

Upvotes: 8

Jonathan Moffatt
Jonathan Moffatt

Reputation: 13457

Styling file inputs are notoriously difficult, as most browsers will not change the appearance from either CSS or javascript.

Even the size of the input will not respond to the likes of:

<input type="file" style="width:200px">

Instead, you will need to use the size attribute:

<input type="file" size="60" />

For any styling more sophisticated than that (e.g. changing the look of the browse button) you will need to look at the tricksy approach of overlaying a styled button and input box on top of the native file input. The article already mentioned by rm at www.quirksmode.org/dom/inputfile.html is the best one I've seen.

UPDATE

Although it's difficult to style an <input> tag directly, this is easily possible with the help of a <label> tag. See answer below from @JoshCrozier: https://stackoverflow.com/a/25825731/10128619

Upvotes: 307

Taio
Taio

Reputation: 3724

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

Upvotes: 3

teshguru
teshguru

Reputation: 3533

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.

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

function sub(obj) {
  var file = obj.value;
  var fileName = file.split("\\");
  document.getElementById("yourBtn").innerHTML = fileName[fileName.length - 1];
  document.myForm.submit();
  event.preventDefault();
}
#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;
}
<form action="#type your action here" method="POST" enctype="multipart/form-data" name="myForm">
  <div id="yourBtn" onclick="getFile()">click to upload a file</div>
  <!-- this is your file input tag, so i hide it!-->
  <!-- i used the onchange event to fire the form submission-->
  <div style='height: 0px;width: 0px; overflow:hidden;'><input id="upfile" type="file" value="upload" onchange="sub(this)" /></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>

Upvotes: 219

kevcha
kevcha

Reputation: 1012

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 !

Upvotes: 35

Tigran Babajanyan
Tigran Babajanyan

Reputation: 2025

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

Upvotes: 16

Despertaweb
Despertaweb

Reputation: 1820

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

Upvotes: 2

James Marquez
James Marquez

Reputation: 375

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

Upvotes: 3

Abdallah Okasha
Abdallah Okasha

Reputation: 2139

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

Upvotes: 6

Rusty Rob
Rusty Rob

Reputation: 17173

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>

Upvotes: 5

personal_cloud
personal_cloud

Reputation: 4494

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.

Upvotes: 4

Johan Hoeksma
Johan Hoeksma

Reputation: 3746

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/

Upvotes: 4

Tomas Crofty
Tomas Crofty

Reputation: 187

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.

Upvotes: -1

r3wt
r3wt

Reputation: 4742

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

Upvotes: 1

Related Questions