Piplup
@piplup/rhf-adaptersmui-file-inputComponents

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

On this page