266
votes

I'd like to make a click event fire on an <input type="file"> tag programmatically.

Just calling click() doesn't seem to do anything or at least it doesn't pop up a file selection dialog.

I've been experimenting with capturing events using listeners and redirecting the event, but I haven't been able to get that to actually perform the event like someone clicked on it.

28
The click event you trigger must be called within a click event started by the user, or it won't work.Umagon

28 Answers

81
votes

You cannot do that in all browsers, supposedly IE does allow it, but Mozilla and Opera do not.

When you compose a message in GMail, the 'attach files' feature is implemented one way for IE and any browser that supports this, and then implemented another way for Firefox and those browsers that do not.

I don't know why you cannot do it, but one thing that is a security risk, and which you are not allowed to do in any browser, is programmatically set the file name on the HTML File element.

261
votes

I have been searching for solution to this whole day. And these are the conclusions that I have made:

  1. For the security reasons Opera and Firefox don't allow to trigger file input.
  2. The only convenient alternative is to create a "hidden" file input (using opacity, not "hidden" or "display: none"!) and afterwards create the button "below" it. In this way the button is seen but on user click it actually activates the file input.

Hope this helps! :)

<div style="display: block; width: 100px; height: 20px; overflow: hidden;">
<button style="width: 110px; height: 30px; position: relative; top: -5px; left: -5px;"><a href="javascript: void(0)">Upload File</a></button>
<input type="file" id="upload_input" name="upload" style="font-size: 50px; width: 120px; opacity: 0; filter:alpha(opacity=0);  position: relative; top: -40px;; left: -20px" />
</div>
68
votes

You can fire click() on any browser but some browsers need the element to be visible and focused. Here's a jQuery example:

$('#input_element').show();
$('#input_element').focus();
$('#input_element').click();
$('#input_element').hide();

It works with the hide before the click() but I don't know if it works without calling the show method. Never tried this on Opera, I tested on IE/FF/Safari/Chrome and it works. I hope this will help.

30
votes

THIS IS POSSIBLE: Under FF4+, Opera ?, Chrome: but:

  1. inputElement.click() should be called from user action context! (not script execution context)

  2. <input type="file" /> should be visible (inputElement.style.display !== 'none') (you can hide it with visibility or something other, but not "display" property)

10
votes

For those who understand that you have to overlay an invisible form over the link, but are too lazy to write, I wrote it for you. Well, for me, but might as well share. Comments are welcome.

HTML (Somewhere):

<a id="fileLink" href="javascript:fileBrowse();" onmouseover="fileMove();">File Browse</a>

HTML (Somewhere you don't care about):

<div id="uploadForm" style="filter:alpha(opacity=0); opacity: 0.0; width: 300px; cursor: pointer;">
    <form method="POST" enctype="multipart/form-data">
        <input type="file" name="file" />
    </form>
</div>

JavaScript:

function pageY(el) {
    var ot = 0;
    while (el && el.offsetParent != el) {
        ot += el.offsetTop ? el.offsetTop : 0;
        el = el.offsetParent;
    }
    return ot;
}

function pageX(el) {
    var ol = 0;
    while (el && el.offsetParent != el) {
        ol += el.offsetLeft ? el.offsetLeft : 0;
        el = el.offsetParent;
    }
    return ol;
}

function fileMove() {
    if (navigator.appName == "Microsoft Internet Explorer") {
        return; // Don't need to do this in IE. 
    }
    var link = document.getElementById("fileLink");
    var form = document.getElementById("uploadForm");
    var x = pageX(link);
    var y = pageY(link);
    form.style.position = 'absolute';
    form.style.left = x + 'px';
    form.style.top = y + 'px';
}

function fileBrowse() {
    // This works in IE only. Doesn't do jack in FF. :( 
    var browseField = document.getElementById("uploadForm").file;
    browseField.click();
}
10
votes

just use a label tag, that way you can hide the input, and make it work through its related label https://developer.mozilla.org/fr/docs/Web/HTML/Element/Label

7
votes

If you want the click method to work on Chrome, Firefox, etc, apply the following style to your input file. It will be perfectly hidden, it's like you do a display: none;

#fileInput {
    visibility: hidden;
    position: absolute;
    top: 0;
    left: -5000px;
}

It's that simple, I tested it works!

5
votes
$(document).one('mousemove', function() { $(element).trigger('click') } );

Worked for me when I ran into similar problem, it's a regular eRube Goldberg.

4
votes

WORKING SOLUTION

Let me add to this old post, a working solution I used to use that works in probably 80% or more of all browsers both new and old.

The solution is complex yet simple. The first step is to make use of CSS and guise the input file type with "under-elements" that show through as it has an opacity of 0. The next step is to use JavaScript to update its label as needed.

HTML The ID's are simply inserted if you wanted a quick way to access a specific element, the classes however, are a must as they relate to the CSS that sets this whole process up

<div class="file-input wrapper">
    <input id="inpFile0" type="file" class="file-input control" />
    <div class="file-input content">
        <label id="inpFileOutput0" for="inpFileButton" class="file-input output">Click Here</label>
        <input id="inpFileButton0" type="button" class="file-input button" value="Select File" />
    </div>
</div>

CSS Keep in mind, coloring and font-styles and such are totally your preference, if you use this basic CSS, you can always use after-end mark up to style as you please, this is shown in the jsFiddle listed at the end.

.file-test-area {
    border: 1px solid;
    margin: .5em;
    padding: 1em;
}
.file-input {
    cursor: pointer !important;
}
.file-input * {
    cursor: pointer !important;
    display: inline-block;
}
.file-input.wrapper {
    display: inline-block;
    font-size: 14px;
    height: auto;
    overflow: hidden;
    position: relative;
    width: auto;
}
.file-input.control {
    -moz-opacity:0 ;
    filter:alpha(opacity: 0);
    opacity: 0;

    height: 100%;
    position: absolute;
    text-align: right;
    width: 100%;
    z-index: 2;
}
.file-input.content {
    position: relative;
    top: 0px;
    left: 0px;
    z-index: 1;
}
.file-input.output {
    background-color: #FFC;
    font-size: .8em;
    padding: .2em .2em .2em .4em;
    text-align: center;
    width: 10em;
}
.file-input.button {
    border: none;
    font-weight: bold;
    margin-left: .25em;
    padding: 0 .25em;
}

JavaScript Pure and true, however, some OLDER (retired) browsers may still have trouble with it (like Netscrape 2!)

var inp = document.getElementsByTagName('input');
for (var i=0;i<inp.length;i++) {
    if (inp[i].type != 'file') continue;
    inp[i].relatedElement = inp[i].parentNode.getElementsByTagName('label')[0];
    inp[i].onchange /*= inp[i].onmouseout*/ = function () {
        this.relatedElement.innerHTML = this.value;
    };
};

Working jsFiddle Example

4
votes

It works :

For security reasons on Firefox and Opera, you can't fire the click on file input, but you can simulate with MouseEvents :

<script>
click=function(element){
    if(element!=null){
        try {element.click();}
        catch(e) {
            var evt = document.createEvent("MouseEvents");
            evt.initMouseEvent("click",true,true,window,0,0,0,0,0,false,false,false,false,0,null);
            element.dispatchEvent(evt);
            }
        }
    };
</script>

<input type="button" value="upload" onclick="click(document.getElementById('inputFile'));"><input type="file" id="inputFile" style="display:none">
4
votes

I know this is old, and all these solutions are hacks around browser security precautions with real value.

That said, as of today, fileInput.click() works in current Chrome (36.0.1985.125 m) and current Firefox ESR (24.7.0), but not in current IE (11.0.9600.17207). Overlaying a file field with opacity 0 on top of a button works, but I wanted a link element as the visible trigger, and hover underlining doesn't quite work in any browser. It flashes on then disappears, probably the browser thinking through whether hover styling actually applies or not.

But I did find a solution that works in all those browsers. I won't claim to have tested every version of every browser, or that I know it'll continue to work forever, but it appears to meet my needs now.

It's simple: Position the file input field offscreen (position: absolute; top: -5000px), put a label element around it, and trigger the click on the label, instead of the file field itself.

Note that the link does need to be scripted to call the click method of the label, it doesn't do that automatically, like when you click on text inside a label element. Apparently the link element captures the click, and it doesn't make it through to the label.

Note also that this doesn't provide a way to show the currently selected file, since the field is offscreen. I wanted to submit immediately when a file was selected, so that's not a problem for me, but you'll need a somewhat different approach if your situation is different.

4
votes

JS Fiddle: http://jsfiddle.net/eyedean/1bw357kw/

popFileSelector = function() {
    var el = document.getElementById("fileElem");
    if (el) {
        el.click();  
    }
};

window.popRightAway = function() {
    document.getElementById('log').innerHTML += 'I am right away!<br />';
    popFileSelector();
};

window.popWithDelay = function() {
    document.getElementById('log').innerHTML += 'I am gonna delay!<br />';
    window.setTimeout(function() {
        document.getElementById('log').innerHTML += 'I was delayed!<br />';
        popFileSelector();
    }, 1000);
};
<body>
  <form>
      <input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)" />
  </form>
  <a onclick="popRightAway()" href="#">Pop Now</a>
    <br />
  <a onclick="popWithDelay()" href="#">Pop With 1 Second Delay</a>
    <div id="log">Log: <br /></div>
</body>
3
votes

This code works for me. Is this what you are trying to do?

<input type="file" style="position:absolute;left:-999px;" id="fileinput" />
<button  id="addfiles" >Add files</button>

<script language="javascript" type="text/javascript">
   $("#addfiles").click(function(){
      $("#fileinput").click();
   });
</script>
3
votes

My solution for Safari with jQuery and jQuery-ui:

$("<input type='file' class='ui-helper-hidden-accessible' />").appendTo("body").focus().trigger('click');
3
votes

Here is pure JavaScript solution to this problem. Works well across all browsers

<script>
    function upload_image_init(){
        var elem = document.getElementById('file');
        if(elem && document.createEvent) {
           var evt = document.createEvent("MouseEvents");
           evt.initEvent("click", true, false);
           elem.dispatchEvent(evt);
        }
    }
</script>
2
votes

There are ways to redirect events to the control but don't expect to be able to easily fire events to the fire control yourself as the browsers will try to block that for (good) security reasons.

If you only need the file dialog to show up when a user clicks something, let's say because you want better looking file upload buttons, then you might want to take a look at what Shaun Inman came up with.

I've been able to achieve keyboard triggering with creative shifting of focus in and out of the control between keydown, keypress & keyup events. YMMV.

My sincere advice is to leave this the alone, because this is a world of browser-incompatibility-pain. Minor browser updates may also block tricks without warning and you may have to keep reinventing hacks to keep it working.

2
votes

I was researching this a while ago because I wanted to create a custom button that would open the file dialog and start the upload immediately. I just noticed something that might make this possible - firefox seems to open the dialog when you click anywhere on the upload. So the following might do it:

  1. Create a file upload and a separate element containing an image that you want to use as the button
  2. Arrange them to overlap and make the file element backgroud and border transparent so the button is the only thing visible
  3. Add the javascript to make IE open the dialog when the button/file input is clicked
  4. Use an onchange event to submit the form when a file is selected

This is only theoretical since I already used another method to solve the problem but it just might work.

2
votes

I had a <input type="button"> tag hidden from view. What I did was attaching the "onClick" event to any visible component of any type such as a label. This was done using either Google Chrome's Developer Tools or Mozilla Firefox's Firebug using the right-click "edit HTML" command. In this event specify the following script or something similar:

If you have JQuery:

$('#id_of_component').click();

if not:

document.getElementById('id_of_component').click();

Thanks.

2
votes

Hey this solution works. for download we should be using MSBLOB

$scope.getSingleInvoicePDF = function(invoiceNumberEntity) {
   var fileName = invoiceNumberEntity + ".pdf";
   var pdfDownload = document.createElement("a");
   document.body.appendChild(pdfDownload);

   AngularWebService.getFileWithSuffix("ezbillpdfget",invoiceNumberEntity,"pdf" ).then(function(returnedJSON) {
       var fileBlob = new Blob([returnedJSON.data], {type: 'application/pdf'});
       if (navigator.appVersion.toString().indexOf('.NET') > 0) { // for IE browser
           window.navigator.msSaveBlob(fileBlob, fileName);
       } else { // for other browsers
           var fileURL = window.URL.createObjectURL(fileBlob);
           pdfDownload.href = fileURL;
           pdfDownload.download = fileName;
           pdfDownload.click();      
       }
   });
};

For AngularJS or even for normal javascript.

1
votes

This will now be possible in Firefox 4, with the caveat that it counts as a pop-up window and will therefore be blocked whenever a pop-up window would have been.

1
votes

Here is solution that work for me: CSS:

#uploadtruefield {
    left: 225px;
    opacity: 0;
    position: absolute;
    right: 0;
    top: 266px;
    opacity:0;
    -moz-opacity:0;
    filter:alpha(opacity:0);
    width: 270px;
    z-index: 2;
}

.uploadmask {
    background:url(../img/browse.gif) no-repeat 100% 50%;
}
#uploadmaskfield{
    width:132px;
}

HTML with "small" JQuery help:

<div class="uploadmask">
    <input id="uploadmaskfield" type="text" name="uploadmaskfield">
</div>
<input id="uploadtruefield"  type="file" onchange="$('#uploadmaskfield').val(this.value)" >

Just be sure that maskfied is covered compeltly by true upload field.

1
votes

You can do this as per answer from Open File Dialog box on <a> tag

<input type="file" id="upload" name="upload" style="visibility: hidden; width: 1px;     height: 1px" multiple />
<a href="" onclick="document.getElementById('upload').click(); return false">Upload</a>
1
votes

I found that if input(file) is outside form, then firing click event invokes file dialog.

1
votes

Hopefully this helps someone - I spent 2 hours banging my head against it:

In IE8 or IE9, if you trigger opening a file input with javascript in any way at all (believe me I've tried them all), it won't let you submit the form using javascript, it will just silently fail.

Submitting the form via a regular submit button may work but calling form.submit(); will silently fail.

I had to resort to overlaying my select file button with a transparent file input which works.

1
votes

This worked for me:

<script>
    function sel_file() {
        $("input[name=userfile]").trigger('click');
    }  
</script>

<input type="file" name="userfile" id="userfile" />

<a href="javascript:sel_file();">Click</a>
1
votes

it's not impossible:

var evObj = document.createEvent('MouseEvents');
evObj.initMouseEvent('click', true, true, window);  
setTimeout(function(){ document.getElementById('input_field_id').dispatchEvent(evObj); },100);

But somehow it works only if this is in a function which was called via a click-event.

So you might have following setup:

html:

<div onclick="openFileChooser()" class="some_fancy_stuff">Click here to open image chooser</div>
<input type="file" id="input_img">

JavaScript:

    function openFileChooser() {
      var evObj = document.createEvent('MouseEvents');
      evObj.initMouseEvent('click', true, true, window);  
      setTimeout(function()
      { 
        document.getElementById('input_img').dispatchEvent(evObj);      
      },100);      
    }
0
votes

You can use

<button id="file">select file</button>
<input type="file" name="file" id="file_input" style="display:none;">
<script>
$('#file').click(function() {
        $('#file_input').focus().trigger('click');
    });
</script>