2

I can't find a proper way of handling a multiple files input using Formik and React.

import { Formik, Field } from "formik";

const MyForm = () => {
  const handleOnSubmit = (actions) => {
    actions.setFieldValue("files", "");
  };

  return (
    <Formik initialValues={{ files: "" }} onSubmit={handleOnSubmit}>
      {({ values, handleSubmit }) => (
        <form onSubmit={handleSubmit}>
          <Field
            id="files"
            name="files"
            type="file"
            multiple
            value={values.files}
            onChange={(event) => {
              setFieldValue("files", Array.from(event.target.files));
            }}
          />
          <button type="submit">Submit</button>
        </form>
      )}
    </Formik>
  );
};

If you pass value={values.files} you get an InvalidStateError:

Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string.

If you pass value={values.files ? undefined : ""} works but you get the React warning:

A component is changing an uncontrolled input to be controlled.

If you pass value={undefined} you don't get to control the input value (for emptying the file selection on form submit).

And if you pass value="" you don't get the name of the selected file (or the number of select files) when selecting files on the input.

Am I missing something? Thank you.

Check an example at Codesandbox.io.

2 Answers 2

1
+50

You can use the useRef to get reference to the file input and clear it like this.

import { Formik, Field } from "formik";
import { useRef } from "react";

export default function App() {
  const fileRef = useRef();

  return (
    <div className="App">
      <Formik
        initialValues={{ files: null }}
        onSubmit={console.log}
      >
        {({ setFieldValue, handleSubmit }) => (
          <form onSubmit={handleSubmit}>
            <Field
              innerRef={fileRef}
              name="files"
              type="file"
              multiple
            />
            <button type="submit">Submit</button>
          </form>
        )}
      </Formik>
      <button onClick={() => (fileRef.current.value = null)}>Clear</button>
    </div>
  );
}

Sign up to request clarification or add additional context in comments.

1 Comment

Seems to be working but I had ot add value={undefined} to avoid the InvalidStateError runtime error after selecting a file.
0

I managed to get your example working by setting files to event.currentTarget.files and using a <input/> instead of Formik's <Field/>.

import { Formik } from "formik";

export default function App() {
  return (
    <div className="App">
      <Formik
        initialValues={{ files: null }}
        onSubmit={(values) => {
          console.log(values);
        }}
      >
        {({ setFieldValue, handleSubmit }) => (
          <form onSubmit={handleSubmit}>
            <input
              name="files"
              type="file"
              multiple
              onChange={(event) => {
                setFieldValue("files", event.currentTarget.files);
              }}
            />
            <button type="submit">Submit</button>
          </form>
        )}
      </Formik>
    </div>
  );
}

You can check out a sandbox here.

1 Comment

I see. But this way, you can't reset the input valie to clear out the file selection.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.