MuiFileInputElement
A mui-file-input field connected to React Hook Form that stores a File, or a File[] with multiple, and supports size and type validation.
MuiFileInputElement renders MuiFileInput from mui-file-input and stores the selected file in React Hook Form: a File (or null) by default, or a File[] when multiple is set. To build your own file field, use useMuiFileInputAdapter.
Import
import { MuiFileInputElement } from "@piplup/rhf-adapters/mui-file-input";Usage
"use client";import Stack from "@mui/material/Stack";import { MuiFileInputElement } from "@piplup/rhf-adapters/mui-file-input";import { MuiButtonElement } from "@piplup/rhf-adapters/mui-material";import { useForm } from "react-hook-form";export default function Page() { const { control, handleSubmit } = useForm({ defaultValues: { resume: null }, }); return ( <form onSubmit={handleSubmit((values) => alert(JSON.stringify(values, null, 2)), )} > <Stack direction="column" spacing={2}> <MuiFileInputElement control={control} name="resume" label="Resume" /> <div> <MuiButtonElement control={control} type="submit" variant="contained"> Submit </MuiButtonElement> </div> </Stack> </form> );}JSON.stringify turns a File into {}, which is why the alert above shows an empty object. Read name, size and type from the File instead, or append it to a FormData to upload it.
Validating files
The element has no size or type options of its own. Write those checks as rules.validate functions; they receive the File or File[] from the form. This demo accepts up to three images of 1 MB or less, and the Reset button clears the selection.
"use client";import Button from "@mui/material/Button";import Stack from "@mui/material/Stack";import { MuiFileInputElement } from "@piplup/rhf-adapters/mui-file-input";import { MuiButtonElement } from "@piplup/rhf-adapters/mui-material";import { useForm } from "react-hook-form";const MAX_SIZE = 1024 * 1024; // 1 MBtype FormValues = { photos: File[] };export default function Page() { const { control, handleSubmit, reset } = useForm<FormValues>({ defaultValues: { photos: [] }, }); return ( <form noValidate onSubmit={handleSubmit((values) => // File objects serialize to {} with JSON.stringify, so list them by hand. alert( values.photos.map((file) => `${file.name} (${Math.round(file.size / 1024)} KB)`).join("\n"), ), )} > <Stack direction="column" spacing={2}> <MuiFileInputElement control={control} name="photos" label="Photos" placeholder="Choose up to 3 images" multiple required messages={{ required: "Attach at least one photo" }} // `accept` only filters the browser's file picker. The rules below enforce it. slotProps={{ htmlInput: { accept: "image/*" } }} rules={{ validate: { count: (files) => files.length <= 3 || "Attach up to 3 photos", type: (files) => files.every((file) => file.type.startsWith("image/")) || "Only image files are allowed", size: (files) => files.every((file) => file.size <= MAX_SIZE) || "Each photo must be 1 MB or smaller", }, }} /> <Stack direction="row" spacing={1}> <MuiButtonElement control={control} variant="contained" type="submit"> Upload </MuiButtonElement> <Button variant="outlined" onClick={() => reset()}> Reset </Button> </Stack> </Stack> </form> );}slotProps.htmlInput.accept only filters what the browser's file picker shows. Users can still choose "All files", so keep a type check in your rules.
How it works
Single vs. multiple. Without multiple, the form value is a File, or null when nothing is selected or the clear button is pressed. With multiple, it is always an array: [] when empty. A value that isn't an array (for example undefined from missing defaultValues) is shown as [] in multiple mode and as null otherwise.
Set multiple on the element, not through slotProps.htmlInput.multiple. With the latter, the browser lets users pick several files but only the first one is stored.
Rules. required fails for null and for an empty array, with the default message "Please fill out this field." Text rules (minLength, maxLength, min, max, pattern) are not supported. To limit the number of files, check files.length in rules.validate.
Resetting. reset() or setValue(name, null) clears the field, and the element also clears the underlying <input type="file">, so the same file can be chosen again afterwards.
Errors and helper text. While the field is invalid, its error message replaces helperText.
Refs. inputRef is merged with React Hook Form's ref. A ref on the element goes to the MuiFileInput root.
Props
Prop
Type