Styling an input type="file" button

Viewed 1577544

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

<input type="file" />

46 Answers

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

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>

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

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

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

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.

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

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

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>

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

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

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

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>

Related