DEV Community

Emeka Orji
Emeka Orji

Posted on

Programmatically Setting File Inputs in JavaScript

Setting the value of a text or number input is as simple as doing

const input = document.querySelector('input');
input.value = 'new value';
Enter fullscreen mode Exit fullscreen mode

However, the situation is slightly different for file inputs. Unlike text or number fields, simply setting the value of a file input is ineffective.

Here is what the value of a file input looks like when the user selects a file manually

input.addEventListener('change', (event) => {
  console.log(event.target.value);
  // => C:\\fakepath\\file.txt
});
Enter fullscreen mode Exit fullscreen mode

Common Misconceptions and Attempts

The path to the file C:\\fakepath\\file.txt on the user's system is obscured from the browser, and setting the value property to something else wouldn't make any difference as the browser does not rely on the value of the input to get a reference to the file. Under the hood, the browser keeps an internal reference to the file on the user's disk, but this is not available to the DOM and should not be changed. You can modify the file, however, by programmatically setting the file property on the input element.

And, no, it is not as simple as doing:

const file = 'path/to/my_file.ext';
input.files = file;

// OR

input.files[0] = file;
Enter fullscreen mode Exit fullscreen mode

Or creating a file object and assigning it to files[0].

const myFile = new File(['My File Content'], 'my_file.txt');

input.files[0] = myFile; // WON'T WORK

input.files = [myFile]; // WON'T WORK
Enter fullscreen mode Exit fullscreen mode

That wouldn't work either as the files object, which is a type of the FileList interface, is not internally an array, but an array-like object. See w3c specification here

My Approach

While searching for answers, I got a bunch of frowning faces and NOs from Stackoverflow. One answer says to a PHP user that if there's a workaround, it will eventually be disabled by Chrome builders. However, this is not the case with the solution here as to disable this would be to disable the drag and drop feature simulation (which is used in most testing libraries), custom drag/drop interaction, or custom clipboard operations. The drag-and-drop feature is what the solution is based on.

Here is it:

const fileInput = document.querySelector('input[type="file"]');

// Get your file ready
const myFileContent = ['My File Content'];
const myFileName = 'my_file.txt';
const myFile = new File(myFileContent, myFileName);

// Create a data transfer object. Similar to what you get from a `drop` event as `event.dataTransfer`
const dataTransfer = new DataTransfer();

// Add your file to the file list of the object
dataTransfer.items.add(file);

// Save the file list to a new variable
const fileList = dataTransfer.files;

// Set your input `files` to the file list
fileInput.files = fileList;
Enter fullscreen mode Exit fullscreen mode

Depending on your use case, you can trigger a change and/or input event to simulate an actual user interaction

fileInput.dispatchEvent(new Event('change', { bubbles: true }));

// AND/OR

fileInput.dispatchEvent(new Event('input', { bubbles: true }));
Enter fullscreen mode Exit fullscreen mode

In my case, I had a problem where I needed to change the file content of a file input field in a form of which I had no access to the code. The forms underlying code watched for file input changes or the dragover/drop JavaScript event. This solution helped me in perfectly simulating a user interaction, I hope it works for your use case, too.

Top comments (4)

Collapse
 
meldulcio profile image
Melchisedek Dulcio

That is was exactly what I needed. Thanks!

Collapse
 
nerdoc profile image
Christian González

small typo: dataTransfer.items.add(file); should be dataTransfer.items.add(myFile);

Collapse
 
aldoanizio profile image
Aldo Anizio Lugão Camacho

Awesome!!!

Collapse
 
maelkmark profile image
Márk Magyar

Thank you very much!