560

Is it possible to clear an <input type='file' /> control value with jQuery? I've tried the following:

$('#control').attr({ value: '' }); 

But it's not working.

0

27 Answers 27

533

Easy: you wrap a <form> around the element, call reset on the form, then remove the form using .unwrap(). Unlike the .clone() solutions otherwise in this thread, you end up with the same element at the end (including custom properties that were set on it).

Tested and working in Opera, Firefox, Safari, Chrome and IE6+. Also works on other types of form elements, with the exception of type="hidden".

window.reset = function(e) {
  e.wrap('<form>').closest('form').get(0).reset();
  e.unwrap();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<form>
  <input id="file" type="file">
  <br>
  <input id="text" type="text" value="Original">
</form>

<button onclick="reset($('#file'))">Reset file</button>
<button onclick="reset($('#text'))">Reset text</button>

JSFiddle

As Timo notes below, if you have the buttons to trigger the reset of the field inside of the <form>, you must call .preventDefault() on the event to prevent the <button> from triggering a submit.


EDIT

Does not work in IE 11 due to an unfixed bug. The text (file name) is cleared on the input, but its File list remains populated.

10
  • 14
    Winner! Works in every browser and avoids cloning input field. But if clear-buttons are inside form, please rename reset() to eg. reset2(), because at least in Chrome all fields are cleared if it is reset(). And add event.preventDefault() after clearing call to prevent submitting. This way: <button onclick="reset2($('#file'));event.preventDefault()">Reset file</button>. Working example: jsfiddle.net/rPaZQ/23. Commented Mar 25, 2013 at 1:49
  • 1
    @Timo, I've renamed the function to resetFormElement and added a note that you should preventDefault() on the button onclick.
    – slipheed
    Commented Mar 25, 2013 at 14:22
  • 28
    Problem is, this at least temporarily makes the document invalid. (Forms can not contain other forms.) Whether it currently works or not, it's free to break any time it wants.
    – cHao
    Commented May 9, 2013 at 13:34
  • 6
    @cHao, of course this is only true if the input element is actually in a form, which it does not have to be. Commented Aug 12, 2013 at 21:59
  • 2
    Latest Chrome doesn't like it (get(0) is undefined), I had to do .wrap('<form></form>'), as advised in jQuery doc anyway.
    – PhiLho
    Commented Dec 1, 2015 at 17:00
435

Quick answer: replace it.

In the code below I use the replaceWith jQuery method to replace the control with a clone of itself. In the event you have any handlers bound to events on this control, we'll want to preserve those as well. To do this we pass in true as the first parameter of the clone method.

<input type="file" id="control"/>
<button id="clear">Clear</button>
var control = $("#control");

$("#clear").on("click", function () {
    control.replaceWith( control = control.clone( true ) );
});

Fiddle: http://jsfiddle.net/jonathansampson/dAQVM/

If cloning, while preserving event handlers, presents any issues you could consider using event delegation to handle clicks on this control from a parent element:

$("form").on("focus", "#control", doStuff);

This prevents the need for any handlers to be cloned along with the element when the control is being refreshed.

3
  • 1
    The annoying thing with this solution is that you have to have the element twice in your code, so if someone changes, for example, the name, you have to change your code twice (which is very easy to forget)
    – Casebash
    Commented Oct 6, 2011 at 0:31
  • 50
    You can also use the .clone() method on the field $('#clone').replaceWith($(this).clone());
    – metric152
    Commented Nov 1, 2011 at 17:30
  • 10
    It still doesn't work. It needs to be cleared prior to replacement. So you'd want .val() before .replaceWith(). So it'd be control.val('').replaceWith(...);
    – mnsr
    Commented Dec 7, 2012 at 4:48
114

Jquery is supposed to take care of the cross-browser/older browser issues for you.

This works on modern browsers that I tested: Chromium v25, Firefox v20, Opera v12.14

Using jquery 1.9.1

HTML

<input id="fileopen" type="file" value="" />
<button id="clear">Clear</button>

Jquery

$("#clear").click(function () {
    $("#fileopen").val("");
});

On jsfiddle

The following javascript solution also worked for me on the browsers mention above.

document.getElementById("clear").addEventListener("click", function () {
    document.getElementById("fileopen").value = "";
}, false);

On jsfiddle

I have no way to test with IE, but theoretically this should work. If IE is different enough that the Javascript version does not work because MS have done it in a different way, the jquery method should in my opinion deal with it for you, else it would be worth pointing it out to the jquery team along with the method that IE requires. (I see people saying "this won't work on IE", but no vanilla javascript to show how it does work on IE (supposedly a "security feature"?), perhaps report it as a bug to MS too (if they would count it as such), so that it gets fixed in any newer release)

Like mentioned in another answer, a post on the jquery forum

 if ($.browser.msie) {
      $('#file').replaceWith($('#file').clone());
 } else {
      $('#file').val('');
 }

But jquery have now removed support for browser testing, jquery.browser.

This javascript solution also worked for me, it is the vanilla equivalent of the jquery.replaceWith method.

document.getElementById("clear").addEventListener("click", function () {
    var fileopen = document.getElementById("fileopen"),
        clone = fileopen.cloneNode(true);

    fileopen.parentNode.replaceChild(clone, fileopen);
}, false);

On jsfiddle

The important thing to note is that the cloneNode method does not preserve associated event handlers.

See this example.

document.getElementById("fileopen").addEventListener("change", function () {
    alert("change");
}, false);

document.getElementById("clear").addEventListener("click", function () {
    var fileopen = document.getElementById("fileopen"),
        clone = fileopen.cloneNode(true);

    fileopen.parentNode.replaceChild(clone, fileopen);
}, false);

On jsfiddle

But jquery.clone offers this [*1]

$("#fileopen").change(function () {
    alert("change");
});

$("#clear").click(function () {
    var fileopen = $("#fileopen"),
        clone = fileopen.clone(true);

    fileopen.replaceWith(clone);
});

On jsfiddle

[*1] jquery is able to do this if the events were added by jquery's methods as it keeps a copy in jquery.data, it does not work otherwise, so it's a bit of a cheat/work-around and means things are not compatible between different methods or libraries.

document.getElementById("fileopen").addEventListener("change", function () {
    alert("change");
}, false);

$("#clear").click(function () {
    var fileopen = $("#fileopen"),
        clone = fileopen.clone(true);

    fileopen.replaceWith(clone);
});

On jsfiddle

You can not get the attached event handler direct from the element itself.

Here is the general principle in vanilla javascript, this is how jquery an all other libraries do it (roughly).

(function () {
    var listeners = [];

    function getListeners(node) {
        var length = listeners.length,
            i = 0,
            result = [],
            listener;

        while (i < length) {
            listener = listeners[i];
            if (listener.node === node) {
                result.push(listener);
            }

            i += 1;
        }

        return result;
    }

    function addEventListener(node, type, handler) {
        listeners.push({
            "node": node,
                "type": type,
                "handler": handler
        });

        node.addEventListener(type, handler, false);
    }

    function cloneNode(node, deep, withEvents) {
        var clone = node.cloneNode(deep),
            attached,
            length,
            evt,
            i = 0;

        if (withEvents) {
            attached = getListeners(node);
            if (attached) {
                length = attached.length;
                while (i < length) {
                    evt = attached[i];
                    addEventListener(clone, evt.type, evt.handler);

                    i += 1;
                }
            }
        }

        return clone;
    }

    addEventListener(document.getElementById("fileopen"), "change", function () {
        alert("change");
    });

    addEventListener(document.getElementById("clear"), "click", function () {
        var fileopen = document.getElementById("fileopen"),
            clone = cloneNode(fileopen, true, true);

        fileopen.parentNode.replaceChild(clone, fileopen);
    });
}());

On jsfiddle

Of course jquery and other libraries have all the other support methods required for maintaining such a list, this is just a demonstration.

0
51

For obvious security reasons you can't set the value of a file input, even to an empty string.

All you have to do is reset the form where the field or if you only want to reset the file input of a form containing other fields, use this:

function reset_field (e) {
    e.wrap('<form>').parent('form').trigger('reset');
    e.unwrap();
}​

Here is an exemple: http://jsfiddle.net/v2SZJ/1/

0
43

This works for me.

$("#file").replaceWith($("#file").clone());

http://forum.jquery.com/topic/how-to-clear-a-file-input-in-ie

Hope it helps.

1
  • 1
    Works for me! It's worth noting that if you have any event listeners triggered by a change in the file input then you need to reassign them once you have replaced the input.
    – JCollerton
    Commented Jul 7, 2016 at 8:35
20

In IE8 they made the File Upload field read-only for security. See the IE team blog post:

Historically, the HTML File Upload Control () has been the source of a significant number of information disclosure vulnerabilities. To resolve these issues, two changes were made to the behavior of the control.

To block attacks that rely on “stealing” keystrokes to surreptitiously trick the user into typing a local file path into the control, the File Path edit box is now read-only. The user must explicitly select a file for upload using the File Browse dialog.

Additionally, the “Include local directory path when uploading files” URLAction has been set to "Disable" for the Internet Zone. This change prevents leakage of potentially sensitive local file-system information to the Internet. For instance, rather than submitting the full path C:\users\ericlaw\documents\secret\image.png, Internet Explorer 8 will now submit only the filename image.png.

18

$("#control").val('') is all you need! Tested on Chrome using JQuery 1.11

Other users have tested in Firefox as well.

4
  • 2
    As many other posts on here explain, this isn't cross browser friendly.
    – Tisch
    Commented Oct 30, 2015 at 11:29
  • For my understanding which browsers does this fail in? Commented Dec 6, 2015 at 18:54
  • 1
    Fails in Internet Explorer as input type file is readonly in IE>
    – Lucky
    Commented Feb 26, 2016 at 8:02
  • 5
    Works in chrome and firefox. More than enough.
    – naimul64
    Commented Sep 26, 2017 at 9:51
13

I got stuck with all the options here. Here's a hack that I made which worked:

<form>
 <input type="file">
 <button type="reset" id="file_reset" style="display:none">
</form>

and you can trigger the reset using jQuery with a code similar to this:

$('#file_reset').trigger('click');

(jsfiddle: http://jsfiddle.net/eCbd6/)

1
  • 3
    ok but it will clear the entire form.. not specific file input Commented Jun 23, 2014 at 10:20
8

I ended up with this:

if($.browser.msie || $.browser.webkit){
  // doesn't work with opera and FF
  $(this).after($(this).clone(true)).remove();  
}else{
  this.setAttribute('type', 'text');
  this.setAttribute('type', 'file'); 
}

may not be the most elegant solution, but it work as far as I can tell.

3
  • stackoverflow.com/questions/8378563/…
    – nischayn22
    Commented Mar 19, 2013 at 21:22
  • doesn't work in chrome 34 (linux). replaceWith() method works in both browsers (chrome, firefox) Commented May 1, 2014 at 9:58
  • At the first I must notice "The $.browser has been removed from jquery 1.9" but the last two lines (Changing type attribute to text and then set back it to the file) worked. Additionally I tried to set $('#control').val(''); or in javascript document.getElementById(control).value = ''; and worked too and don't know why we shouldn't using this approach!? Finally, I decided to use both of them.
    – QMaster
    Commented Oct 7, 2018 at 17:04
8

I have used https://github.com/malsup/form/blob/master/jquery.form.js, which has a function called clearInputs(), which is crossbrowser, well tested, easy to use and handles also IE issue and hidden fields clearing if needed. Maybe a little long solution to only clear file input, but if you are dealing with crossbrowser file uploads, then this solution is recommended.

The usage is easy:

// Clear all file fields:
$("input:file").clearInputs();

// Clear also hidden fields:
$("input:file").clearInputs(true);

// Clear specific fields:
$("#myfilefield1,#myfilefield2").clearInputs();
/**
 * Clears the selected form elements.
 */
$.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
    var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
    return this.each(function() {
        var t = this.type, tag = this.tagName.toLowerCase();
        if (re.test(t) || tag == 'textarea') {
            this.value = '';
        }
        else if (t == 'checkbox' || t == 'radio') {
            this.checked = false;
        }
        else if (tag == 'select') {
            this.selectedIndex = -1;
        }
        else if (t == "file") {
            if (/MSIE/.test(navigator.userAgent)) {
                $(this).replaceWith($(this).clone(true));
            } else {
                $(this).val('');
            }
        }
        else if (includeHidden) {
            // includeHidden can be the value true, or it can be a selector string
            // indicating a special test; for example:
            //  $('#myForm').clearForm('.special:hidden')
            // the above would clean hidden inputs that have the class of 'special'
            if ( (includeHidden === true && /hidden/.test(t)) ||
                 (typeof includeHidden == 'string' && $(this).is(includeHidden)) )
                this.value = '';
        }
    });
};
3
  • I don't understand why this answer isn't more upvoted ?!
    – AlexB
    Commented Aug 1, 2014 at 14:30
  • 1
    @AlexB: Because, as Timo explained, it's overkill just to clear one file input field.
    – TheCarver
    Commented Feb 14, 2015 at 2:30
  • Don't know if that worked but no more on FF 45.0.2:(
    – fralbo
    Commented May 5, 2016 at 17:00
5

The value of file inputs is read only (for security reasons). You can't blank it programatically (other than by calling the reset() method of the form, which has a broader scope than just that field).

4
  • 17
    I'm confused - I tried $("#inputControl").val("") and it did indeed blank the field. Am I missing something?
    – Sampson
    Commented Jun 25, 2009 at 15:57
  • 1
    @Jonathan, works for me too, but if you set it to anything else it's a security error. Tested in FF4.
    – Brenden
    Commented Apr 22, 2011 at 22:34
  • reset() is a JS native method so if you select the form via jQuery you need to take the element out of jQuery scope. $("form#myForm")[0].reset(); Commented Jun 27, 2011 at 15:01
  • 5
    @Jonathan It works for you because you did not do it in IE. This security issue is something that only IE stops. Clearing the value regularly works in both Chrome and Firefox, but not IE
    – VoidKing
    Commented Nov 2, 2012 at 15:14
5

I was able to get mine working with the following code:

var input = $("#control");    
input.replaceWith(input.val('').clone(true));
5

I have been looking for simple and clean way to clear HTML file input, the above answers are great, but none of them really answers what i'm looking for, until i came across on the web with simple an elegant way to do it :

var $input = $("#control");

$input.replaceWith($input.val('').clone(true));

all the credit go's to Chris Coyier.

// Referneces
var control = $("#control"),
    clearBn = $("#clear");

// Setup the clear functionality
clearBn.on("click", function(){
    control.replaceWith( control.val('').clone( true ) );
});

// Some bound handlers to preserve when cloning
control.on({
    change: function(){ console.log( "Changed" ) },
     focus: function(){ console.log(  "Focus"  ) }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<input type="file" id="control">
<br><br>
<a href="#" id="clear">Clear</a>

4

The .clone() thing does not work in Opera (and possibly others). It keeps the content.

The closest method here for me was Jonathan's earlier, however ensuring that the field preserved its name, classes, etc made for messy code in my case.

Something like this might work well (thanks to Quentin too):

function clearInput($source) {
    var $form = $('<form>')
    var $targ = $source.clone().appendTo($form)
    $form[0].reset()
    $source.replaceWith($targ)
}
2
  • Has this been tested in all major browsers?
    – Shawn
    Commented Oct 19, 2012 at 17:09
  • It seems to work fine in the latest version of Chrome/FF/Opera, and in IE8. I can't see any reason why it wouldn't work on anything - the reset option on forms has been around a long time.
    – SpoonNZ
    Commented Oct 22, 2012 at 23:22
4

I have managed to get this to work using the following...

function resetFileElement(ele) 
{
    ele.val(''); 
    ele.wrap('<form>').parent('form').trigger('reset');   
    ele.unwrap();
    ele.prop('files')[0] = null;
    ele.replaceWith(ele.clone());    
}

This has been tested in IE10, FF, Chrome & Opera.

There are two caveats...

  1. Still doesn't work properly in FF, if you refresh the page, the file element gets re-populated with the selected file. Where it is getting this info from is beyond me. What else related to a file input element could I possible try to clear?

  2. Remember to use delegation on any events you had attached to the file input element, so they still work when the clone is made.

What I don't understand is who on earth thought not allowing you to clear an input field from an invalid unacceptable file selection was a good idea?

OK, don't let me dynamically set it with a value so I can't leach files from a user's OS, but let me clear an invalid selection without resetting an entire form.

It's not like 'accept' does anything other than a filter anyhow and in IE10, it doesn't even understand MS Word mime types, it's a joke!

1
  • This almost works. The one thing you need to do to make this work in Firefox is to use .pop() on the array of files instead of setting it to null. this seems to clear out the file properly.
    – kmacdonald
    Commented Feb 12, 2015 at 18:47
2

On my Firefox 40.0.3 only work with this

 $('input[type=file]').val('');
 $('input[type=file]').replaceWith($('input[type=file]').clone(true));
1
  • 2
    $('input[type=file]').replaceWith($('input[type=file]').clone(true).val(''));
    – Andrei
    Commented Nov 3, 2016 at 11:51
2

its works for me in every browser.

        var input = $(this);
        var next = this.nextSibling;
        var parent = input.parent();
        var form = $("<form></form>");
        form.append(input);
        form[0].reset();
        if (next) {
            $(next).before(input);
        } else {
            parent.append(input);
        }
1

I tried with the most of the techniques the users mentioned, but none of they worked in all browsers. i.e: clone() doesn't work in FF for file inputs. I ended up copying manually the file input, and then replacing the original with the copied one. It works in all browsers.

<input type="file" id="fileID" class="aClass" name="aName"/>

var $fileInput=$("#fileID");
var $fileCopy=$("<input type='file' class='"+$fileInput.attr("class")+" id='fileID' name='"+$fileInput.attr("name")+"'/>");
$fileInput.replaceWith($fileCopy);
0
0

$("input[type=file]").wrap("<div id='fileWrapper'/>");
$("#fileWrapper").append("<div id='duplicateFile'   style='display:none'>"+$("#fileWrapper").html()+"</div>");
$("#fileWrapper").html($("#duplicateFile").html());
1
  • 1
    Hi Niraj. Welcome. This answer may well be correct but it could use some explanation.
    – tomfanning
    Commented Nov 12, 2012 at 13:26
0

This works with Chrome, FF, and Safari

$("#control").val("")

May not work with IE or Opera

2
  • 1
    Looks almost identical to the very problem in the OP
    – Trindaz
    Commented Dec 20, 2012 at 3:39
  • 1
    is not a ecmascript standard, the value of input type file is a protect property for security reasons.
    – e-info128
    Commented Jul 26, 2013 at 4:24
0

Make it asynchronous, and reset it after the button's desired actions have been done.

    <!-- Html Markup --->
    <input id="btn" type="file" value="Button" onchange="function()" />

    <script>
    //Function
    function function(e) {

        //input your coding here           

        //Reset
        var controlInput = $("#btn");
        controlInput.replaceWith(controlInput = controlInput.val('').clone(true));
    } 
    </script>
0
function clear() {
    var input = document.createElement("input");
    input.setAttribute('type', 'file');
    input.setAttribute('value', '');
    input.setAttribute('id', 'email_attach');

    $('#email_attach').replaceWith( input.cloneNode() );
}
0

it does not work for me:

$('#Attachment').replaceWith($(this).clone());
or 
$('#Attachment').replaceWith($('#Attachment').clone());

so in asp mvc I use razor features for replacing file input. at first create a variable for input string with Id and Name and then use it for showing in page and replacing on reset button click:

@{
    var attachmentInput = Html.TextBoxFor(c => c.Attachment, new { type = "file" });
}

@attachmentInput

<button type="button" onclick="$('#@(Html.IdFor(p => p.Attachment))').replaceWith('@(attachmentInput)');">--</button>
0

An easy way is changing the input type and change it back again.

Something like this:

var input = $('#attachments');
input.prop('type', 'text');
input.prop('type', 'file')
-1

You can replace it with its clone like so

var clone = $('#control').clone();

$('#control').replacewith(clone);

But this clones with its value too so you had better like so

var emtyValue = $('#control').val('');
var clone = emptyValue.clone();

$('#control').replacewith(clone);
-4

It's easy lol (works in all browsers [except opera]):

$('input[type=file]').each(function(){
    $(this).after($(this).clone(true)).remove();
});

JS Fiddle: http://jsfiddle.net/cw84x/1/

2
  • I coudn't care less about opera. Just wrap it in the form then if you care. I personally don't care and I will use my method.
    – Anonymous
    Commented Aug 24, 2012 at 6:46
  • 2
    This isn't a good answer at all but the main problem was the really bad attitude
    – Isaac
    Commented Jan 21, 2016 at 16:51
-5

What? In your validation function, just put

document.onlyform.upload.value="";

Assuming upload is the name:

<input type="file" name="upload" id="csv_doc"/>

I'm using JSP, not sure if that makes a difference...

Works for me, and I think it's way easier.

0