File uploads and validation with React and Formik
Aashutosh Poudel
Posted on March 28, 2022
Formik doesn't provide a way to handle file uploads easily. I found a decent solution looking at various github issues and stackoverflow discussions.
Here is a codesandbox showing how to validate the size of the files as well as their MIME types.
Link: https://codesandbox.io/s/hardcore-ully-tdk4iu?file=/src/App.js
The basic idea behind working with files in Formik is to make the file input component uncontrolled and access the selected files with a ref
. More info here: https://reactjs.org/docs/uncontrolled-components.html#the-file-input-tag
Step 1: We create a ref
inside the form and pass that ref to the file input component.
export default function App() {
const initialValues = {
files: ""
};
const fileRef = useRef(null);
return (
<Formik
initialValues={initialValues}
validationSchema={Yup.object({
files: Yup.mixed()
{/* ... */}
})}
onSubmit={(values) => {
{/* ... */}
}}
>
<Form>
<FileUpload name="files" fileRef={fileRef} />
<button type="submit">Submit</button>
</Form>
</Formik>
);
}
Step 2: Inside the <FileUpload>
component we use the passed ref
as follows:
const FileUpload = ({ fileRef, ...props }) => {
const [field, meta] = useField(props);
return (
<div>
<label htmlFor="files">Choose files</label>{" "}
<input ref={fileRef} multiple={true} type="file" {...field} />
{meta.touched && meta.error ? (
<div style={{ color: "red" }}>{meta.error}</div>
) : null}
</div>
);
};
Step 3: We validate the size of files uploaded and the MIME type of the file as follows:
Note: we are accessing the files directly using ref
.
validationSchema={Yup.object({
files: Yup.mixed()
.test("is-file-too-big", "File exceeds 10MB", () => {
let valid = true;
const files = fileRef?.current?.files;
if (files) {
const fileArr = Array.from(files);
fileArr.forEach((file) => {
const size = file.size / 1024 / 1024;
if (size > 10) {
valid = false;
}
});
}
return valid;
})
.test(
"is-file-of-correct-type",
"File is not of supported type",
() => {
let valid = true;
const files = fileRef?.current?.files;
if (files) {
const fileArr = Array.from(files);
fileArr.forEach((file) => {
const type = file.type.split("/")[1];
const validTypes = [
"zip",
"xml",
"xhtml+xml",
"plain",
"svg+xml",
"rtf",
"pdf",
"jpeg",
"png",
"jpg",
"ogg",
"json",
"html",
"gif",
"csv"
];
if (!validTypes.includes(type)) {
valid = false;
}
});
}
return valid;
}
)
})}
References:
Posted on March 28, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.