121

I have a hidden file input element. Is it possible to trigger its select file dialog box from a button's click event?

tamakisquare
  • 16,659
  • 26
  • 88
  • 129

15 Answers15

165

If you're looking to have your own button to upload a file instead of using <input type="file" />, you can do something like:

<input id="myInput" type="file" style="visibility:hidden" />
<input type="button" value="Show Dialog" onclick="$('#myInput').click();" />

Note that I used visibility: hidden, instead of display: none. You cannot call the click event on a non-displayed file input.

thiagowfx
  • 4,832
  • 6
  • 37
  • 51
Mike Gwilt
  • 2,399
  • 1
  • 16
  • 14
  • Straightforward for basic cases, but not compatible with many browsers. Please note that its a much better idea to combine this solution with overlaying the file input element over a button at opacity:0, as it has been mentioned in Xeon06's answer. – SquareCat Oct 06 '13 at 13:08
  • 14
    Update: In modern browsers you can click an input that's not even in the DOM. Awesome! – Adria Oct 08 '14 at 19:53
  • 8
    i just tried `click()` on a `display:none` input and it worked – Daniel Cheung Jun 27 '15 at 12:44
  • 18
    Yep, here in the year 2015, `click()`ing on an element with `display: none` works! ;) How things have changed in the last four years. – ffxsam Nov 26 '15 at 05:41
  • 1
    You can use `hidden` attribute instead `style="visibility:hidden"`: `` (https://www.w3schools.com/tags/att_global_hidden.asp) – cespon Feb 13 '19 at 14:20
133

Most answers here are lacking a useful information:

Yes, you can programmatically click the input element using jQuery/JavaScript, but only if you do it in an event handler belonging to an event THAT WAS STARTED BY THE USER!

So, for example, nothing will happen if you, the script, programmatically click the button in an ajax callback, but if you put the same line of code in an event handler that was raised by the user, it will work.

P.S. The debugger; keyword disrupts the browse window if it is before the programmatical click ...at least in chrome 33...

Chris Happy
  • 7,088
  • 2
  • 22
  • 49
Fazi
  • 3,909
  • 4
  • 27
  • 23
  • as @LouisBataillard rightfully mentions: not only does the original event handler need to be initiated by the user; it must be specifically a click event. Here is a fiddle he provided demonstrating this: [link](http://jsfiddle.net/UQfaZ/1/) – Souhaieb Besbes Jun 16 '15 at 14:58
  • 1
    you can click something that is dynamically generated. in jquery, that is `$(staticElementParent).on("click", "dynamicChild", function(){})` – Daniel Cheung Jun 27 '15 at 12:47
  • 1
    THANK YOU!!!! I've been testing all these answers in the javascript console and I've been going nuts! – jdkealy Jan 12 '16 at 17:41
  • 8
    I've been struggling for half an hour with programmatically prompting a file input window. NOBODY ELSE stated that it's impossible if the event isn't started by the user... you deserve a lot of +1. – Umagon Apr 17 '16 at 05:36
  • Also, the depth of the stack seems to make a difference. Only the first button works in this example: http://jsfiddle.net/fhfos5c4/ (Mac OS 10.12, Chrome 54.0.2840.98) – geon Nov 17 '16 at 14:58
  • 2
    As of Chrome 62 the `debugger;` keyword no longer disrupts the programmatic click – Chris W. Dec 15 '17 at 15:58
  • In Chrome 87, the console shows a warning: 'File chooser dialog can only be shown with a user activation', and the action fails. In current Firefox, the action fails silently. – VanAlbert Dec 08 '20 at 10:46
  • FireFox now shows _ picker was blocked due to lack of user activation._ – kiatng Jan 20 '22 at 01:13
74

Just for the record, there is an alternative solution that does not require javascript. It is a bit of a hack, exploiting the fact that clicking on a label sets the focus on the associated input.

You need a <label> with a proper for attribute (points to the input), optionnaly styled like a button (with bootstrap, use btn btn-default). When the user clicks the label, the dialog opens, example :

<!-- optionnal, to add a bit of style -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet"/>

<!-- minimal setup -->
<label for="exampleInput" class="btn btn-default">
  Click me
</label>
<input type="file" id="exampleInput" style="display: none" />
m_x
  • 12,357
  • 7
  • 46
  • 60
  • 2
    I like this one, don't want to include full jQuery in my Angular project, works nice :) – Starscream1984 Dec 22 '15 at 10:17
  • 1
    is this behavior reliable in all modern browsers? – JoshuaDavid Jul 11 '17 at 22:51
  • This works without any JS whatsoever, using native browser behavior. Paired with onDrop events, implementing a feature rich file upload works great! – Yanick Rochon Nov 05 '18 at 15:38
  • I had to fiddle with the CSS but then it worked - namely the file input visibility having "display: none" is not ok in all browsers. (But opacity of 0, etc, can be used) – floer32 Dec 07 '19 at 16:41
  • Add pointer-events: none; if you don't want accidental clicks on it. See https://zellwk.com/blog/hide-content-accessibly/ for a discussion of the accessibility implications of various options. – s6mike Dec 11 '22 at 19:41
15

I'm not sure how browsers handle clicks on type="file" elements (security concerns and all), but this should work:

$('input[type="file"]').click();

I've tested this JSFiddle in Chrome, Firefox and Opera and they all show the file browse dialog.

Bojangles
  • 99,427
  • 50
  • 170
  • 208
  • 5
    This seems to work only when the "calling" event is itself a click event. For example it doesn't seem to be possible to open the file dialog based on a `hover` event: http://jsfiddle.net/UQfaZ/1/ – Louis B. Feb 25 '13 at 20:20
  • Do you know how this can be tested with Selenium if the input is not in the DOM? – Sebastien Lorber Feb 18 '16 at 10:24
8

Nowadays a hybrid solution like this can have the best experience,

let fileHandle;
async function fileOpen() {
    [fileHandle] = await window.showOpenFilePicker();
    const file = await fileHandle.getFile();
    console.log(await file.text());
}
// The advantage of this is fileHandle can be used to save to
// the opened file itself later, read more on this in https://web.dev/file-system-access/


// in April 2021, window.showOpenFilePicker still not support in Safari
// so one should have this around also
function legacyFileOpen() {
    var input = document.createElement('input');
    input.type = 'file';
    input.onchange = function () {
        input.files[0].arrayBuffer().then(function (arrayBuffer) {
            console.log(new TextDecoder().decode(arrayBuffer));
        });
    }
    input.click();
}
Ebrahim Byagowi
  • 10,338
  • 4
  • 70
  • 81
  • For anyone using the hybrid approach, you can do a check to see whether the "modern" fileOpen is supported with something like and decide which implementation to call based on the availability of the API. `export const supportsShowOpenFilePicker = 'showOpenFilePicker' in window && typeof window.showOpenFilePicker === 'function'; ` – rcbevans Oct 04 '22 at 19:05
4

The best solution, works in all browsers.. even on mobile.

<div class="btn" id="s_photo">Upload</div>

<input type="file" name="s_file" id="s_file" style="opacity: 0;">';

<!--jquery-->

<script>
    $("#s_photo").click(function() {
        $("#s_file").trigger("click");
    });
</script>

Hiding the input file type causes problems with browsers, opacity is the best solution because it isn't hiding, just not showing. :)

Unmitigated
  • 76,500
  • 11
  • 62
  • 80
Pessa
  • 41
  • 3
  • 1
    you should mention that this requires a jquery reference. – Brino May 15 '15 at 13:17
  • Opacity involves a totally unrelated concept - you're just lucky if it doesn't affect your layout with an "see-through" element. The element should be there, but not visible, so `visibility:hidden` should be a better choice. – conny Jun 23 '15 at 07:03
  • `visibility: hidden` still affects the layout. `display: none` is what you want. – jobukkit Sep 13 '16 at 11:15
4

I wrap the input[type=file] in a label tag, then style the label to your liking, and hide the input.

<label class="btn btn-default fileLabel" data-toggle="tooltip" data-placement="top" title="Upload">
    <input type="file">
    <span><i class="fa fa-upload"></i></span>
</label>

<style>
    .fileLabel input[type="file"] {
        position: fixed;
        top: -1000px;
    }
</style>

Purely CSS Solution.

Ponyboy
  • 956
  • 9
  • 16
3

Natively the only way is by creating an <input type="file"> element and then simulating a click, unfortunately.

There's a tiny plugin (shameless plug) which will take the pain away of having to do this all the time: file-dialog

fileDialog()
    .then(file => {
        const data = new FormData()
        data.append('file', file[0])
        data.append('imageName', 'flower')

        // Post to server
        fetch('/uploadImage', {
            method: 'POST',
            body: data
        })
    })
Alister
  • 27,049
  • 9
  • 40
  • 35
1

Make sure you are using binding to get component props in REACT

class FileUploader extends Component {
  constructor (props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
   onChange=(e,props)=>{
    const files = e.target.files;
    const selectedFile = files[0];
    ProcessFileUpload(selectedFile,props.ProgressCallBack,props.ErrorCallBack,props.CompleatedCallBack,props.BaseURL,props.Location,props.FilesAllowed);
  }
   handleClick = () => {
    this.refs.fileUploader.click();
  }
  render()
  {
  return(
      <div>
        <button type="button" onClick={this.handleClick}>Select File</button>  
        <input type='file' onChange={(e)=>this.onChange(e,this.props)} ref="fileUploader" style={{display:"none"}} />
      </div>)
  }
}
m-farhan
  • 1,436
  • 13
  • 14
1

browse file programatically



function browseFile(accept) {
    const promise = resolvingPromise();
    const input = document.createElement('input');
    input.type = "file";
    input.accept = accept;
    input.onchange = function (e) {
        const files = e.target.files;
        promise.resolve(files);
    }
    setTimeout(function () {
        click(input);
    }, 0);
    return promise;
}

function click(node) {
    try {
        node.dispatchEvent(new MouseEvent('click'))
    } catch (e) {
        const evt = document.createEvent('MouseEvents')
        evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null)
        node.dispatchEvent(evt);
    }
}


francojohnc
  • 717
  • 5
  • 5
1

There is no cross browser way of doing it, for security reasons. What people usually do is overlay the input file over something else and set it's visibility to hidden so it gets triggered on it's own. More info here.

Alex Turpin
  • 46,743
  • 23
  • 113
  • 145
  • 2
    The OP is talking about ``, not ` – Bojangles Dec 21 '11 at 19:47
  • Not a problem. I've done it myself before. In response to your edit, there _is_ a way to do it; by triggering the element's click event with jQuery `$.click()`. – Bojangles Dec 21 '11 at 19:54
  • 1
    @JamWaffles okay that's weird. I clearly remember spending a whole day on this a few weeks back. It didn't work in Firefox and IE afair. I wonder what the deal was... – Alex Turpin Dec 21 '11 at 20:00
  • Curious. I have a JSFiddle in my answer that works with FF. I can't test in IE (I'm on Linux), so I don't know if that will still throw up. – Bojangles Dec 21 '11 at 20:02
  • @JamWaffles oh I saw that, and I just made a small example on my computer and it works flawlessly in all browsers including IE. I seem to remember a problem with the onchange event not being fired on those cases. But then again, just tested it and it all seems to work. – Alex Turpin Dec 21 '11 at 20:04
  • Looking at this answer http://stackoverflow.com/a/1829817/104999, I see I'm not crazy. There was a hack to get it working in IE, and I think the jQuery guys must have implemented it in a more recent version. As for Firefox, it must have been updated to support it. – Alex Turpin Dec 21 '11 at 20:05
  • Indeed. Mystery solved! http://bugs.jquery.com/ticket/8866 https://developer.mozilla.org/en/using_files_from_web_applications#Using_hidden_file_input_elements_using_the_click()_method – Alex Turpin Dec 21 '11 at 20:08
  • 2
    Good research effort there! If I go a penny for every time web developers had to hack some pretty normal behaviour into something, I'd be filthy rich. – Bojangles Dec 21 '11 at 20:10
  • Well that would have bugged me all week if I hadn't remembered. Now I'm gonna go change that nasty hack and make it clean :D – Alex Turpin Dec 21 '11 at 20:11
0

This worked for me:

$('#fileInput').val('');
Undo
  • 25,519
  • 37
  • 106
  • 129
dileepar
  • 171
  • 2
  • 5
0

For those who want the same but are using React

openFileInput = () => {
    this.fileInput.click()
}

<a href="#" onClick={this.openFileInput}>
    <p>Carregue sua foto de perfil</p>
    <img src={img} />
</a>
<input style={{display:'none'}} ref={(input) => { this.fileInput = input; }} type="file"/>
Vinicius Lima
  • 1,601
  • 1
  • 12
  • 15
0
<div id="uploadButton">UPLOAD</div>
<form action="[FILE_HANDLER_URL]" style="display:none">
     <input id="myInput" type="file" />
</form>
<script>
  const uploadButton = document.getElementById('uploadButton');
  const myInput = document.getElementById('myInput');

  uploadButton.addEventListener('click', () => {
    myInput.click();
  });
</script>
yairniz
  • 408
  • 5
  • 7
0

Using jQuery you can call click() to simulate a click.

pdubs
  • 2,698
  • 1
  • 16
  • 15