useMuiSelectAdapter
Returns props that connect an MUI Select to React Hook Form, including multiple selection, for building a select with its own label and helper text.
useMuiSelectAdapter connects an MUI Select to a React Hook Form field and returns props you spread onto it. It's what MuiSelectElement uses internally.
Select on its own has no label or helper text, so a complete field needs a FormControl, an InputLabel and a FormHelperText around it. The element doesn't render those for you. Use the hook to build that whole field once, with the error message wired in.
Import
import { useMuiSelectAdapter } from "@piplup/rhf-adapters/mui-material";Usage
A multiple select that needs at least one and at most three languages. The helper text switches to the error message when a rule fails.
"use client";import FormControl from "@mui/material/FormControl";import FormHelperText from "@mui/material/FormHelperText";import InputLabel from "@mui/material/InputLabel";import MenuItem from "@mui/material/MenuItem";import Select from "@mui/material/Select";import Stack from "@mui/material/Stack";import { MuiButtonElement, useMuiSelectAdapter,} from "@piplup/rhf-adapters/mui-material";import { type Control, useForm } from "react-hook-form";type FormValues = { languages: string[] };const LANGUAGES = ["English", "French", "German", "Hindi", "Japanese", "Spanish"];const MAX_LANGUAGES = 3;// A multiple select with its label and helper text in one component.// maxLength doesn't apply to arrays, so the limit is a `validate` rule.function LanguagesField({ control }: { control: Control<FormValues> }) { const { error, helperText, ...adapter } = useMuiSelectAdapter< string[], FormValues, "languages", HTMLDivElement >({ control, name: "languages", multiple: true, required: true, composeHelperText: true, helperText: `Up to ${MAX_LANGUAGES} languages`, messages: { required: "Pick at least one language" }, rules: { validate: (value) => value.length <= MAX_LANGUAGES || `Pick ${MAX_LANGUAGES} languages or fewer`, }, }); return ( <FormControl error={error} sx={{ width: 280 }}> <InputLabel id="languages-label">Languages you speak</InputLabel> <Select labelId="languages-label" label="Languages you speak" renderValue={(selected) => (selected as string[]).join(", ")} {...adapter} > {LANGUAGES.map((language) => ( <MenuItem key={language} value={language}> {language} </MenuItem> ))} </Select> <FormHelperText>{helperText}</FormHelperText> </FormControl> );}export default function Page() { const { control, handleSubmit } = useForm<FormValues>({ defaultValues: { languages: [] }, }); return ( <form noValidate onSubmit={handleSubmit((values) => alert(JSON.stringify(values, null, 2)), )} > <Stack direction="column" spacing={2}> <LanguagesField control={control} /> <div> <MuiButtonElement control={control} type="submit" variant="contained"> Submit </MuiButtonElement> </div> </Stack> </form> );}How it works
Single vs multiple. Pass multiple to the hook, not only to Select; the hook returns it so it reaches Select when you spread. With multiple, a field value that isn't an array (such as undefined) is passed to Select as []. Without it, the field value is passed through unchanged.
Stored value. On change, the hook stores event.target.value: the selected MenuItem value, or the array of selected values with multiple. Use transform.output to store something else.
Validation. required fails for an empty string and for an empty array, so it works for both modes. React Hook Form's minLength and maxLength don't apply to arrays, so limit the number of selections with rules.validate, as the demo does.
Errors and helper text. Select accepts error but has no helperText prop. Render the returned helperText in a FormHelperText, and put error on the FormControl so the label and helper text turn red too. With composeHelperText: true, helperText is the field's error message, falling back to your helperText when there's no error.
For a single select, give the field a default value such as "" in useForm's defaultValues. Without one, Select receives undefined at first, which MUI treats as uncontrolled, and logs a warning when a value is chosen.
helperText isn't a Select prop. Remove it from the returned object before spreading, as the demo and the element do.
Props
Prop
Type
Return value
Prop
Type
useMuiRatingAdapter
Returns props that connect an MUI Rating to React Hook Form, with null for no rating and min/max turned into validation rules.
useMuiSliderAdapter
Returns props that connect an MUI Slider to React Hook Form, for single and range sliders, with fallbacks for empty values and transforms for custom shapes.