useMuiAutocompleteAdapter
Returns props that connect an MUI Autocomplete to React Hook Form, passing error, helperText and required into renderInput and supporting option-to-value transforms.
useMuiAutocompleteAdapter connects an MUI Autocomplete to a React Hook Form field and returns props you spread onto it. It's what MuiAutocompleteElement uses internally.
Use the element for most forms. Reach for the hook when you want a reusable field with its options, labels and messages built in, such as a country or user picker that's used across many forms.
Import
import { useMuiAutocompleteAdapter } from "@piplup/rhf-adapters/mui-material";Usage
The options are { code, label } objects, but the form stores only the code ("IN"). The transform maps the code to its option for display and back to a code on change. Clear the field and submit to see the error in the text field's helper text.
"use client";import Autocomplete from "@mui/material/Autocomplete";import Stack from "@mui/material/Stack";import TextField from "@mui/material/TextField";import { MuiButtonElement, useMuiAutocompleteAdapter,} from "@piplup/rhf-adapters/mui-material";import type * as React from "react";import { type Control, useForm } from "react-hook-form";type Country = { code: string; label: string };type FormValues = { country: string | null };const COUNTRIES: Country[] = [ { code: "CA", label: "Canada" }, { code: "DE", label: "Germany" }, { code: "IN", label: "India" }, { code: "JP", label: "Japan" }, { code: "GB", label: "United Kingdom" }, { code: "US", label: "United States" },];// The form stores only the country code. The transform maps the code to an// option object for the Autocomplete and back to a code on change.function CountryField({ control }: { control: Control<FormValues> }) { const adapter = useMuiAutocompleteAdapter< Country | null, false, FormValues, "country", HTMLDivElement >({ control, name: "country", required: true, composeHelperText: true, helperText: "Where should we ship your order?", messages: { required: "Choose a country" }, transform: { input: (code) => COUNTRIES.find((country) => country.code === code) ?? null, output: (_event: React.SyntheticEvent, option: Country | null) => option?.code ?? null, }, // params includes error, helperText and required from the adapter. renderInput: (params) => <TextField {...params} label="Country" />, }); return ( <Autocomplete options={COUNTRIES} getOptionLabel={(option) => option.label} sx={{ width: 300 }} {...adapter} /> );}export default function Page() { const { control, handleSubmit } = useForm<FormValues>({ defaultValues: { country: "IN" }, }); return ( <form noValidate onSubmit={handleSubmit((values) => alert(JSON.stringify(values, null, 2)), )} > <Stack direction="column" spacing={2}> <CountryField control={control} /> <div> <MuiButtonElement control={control} type="submit" variant="contained"> Continue </MuiButtonElement> </div> </Stack> </form> );}How it works
renderInput gets the field state. The returned renderInput calls yours with MUI's usual params plus error, helperText and required. Spread params onto your TextField and it shows the error state, the message and the required asterisk. These three are not returned for the Autocomplete itself.
Turn on composeHelperText. The element sets it for you; the hook doesn't. Without it, params.helperText is only your helperText and validation messages never appear. With it, the error message replaces your helperText while the field is invalid.
Empty values. With multiple, a field value that isn't an array is passed to Autocomplete as []. Without it, undefined becomes null. Pass multiple to the hook; it's returned so it reaches Autocomplete when you spread.
Stored value. On change, the hook stores the value Autocomplete reports: the selected option, the array of options with multiple, or null when cleared. transform.output receives (event, value, reason, details) and returns what to store; transform.input turns the stored value back into an option.
Validation. required fails for null and for an empty array. React Hook Form's minLength and maxLength don't apply to arrays, so limit the number of selected options with rules.validate.
Your transform.input replaces the default one, including the undefined → null / [] handling, so return null (or []) yourself when there's no match. Return the same option objects you pass in options, or set isOptionEqualToValue, so MUI can match the value to an option.
required is passed to your TextField, which puts required on the text input. With multiple, the text input is usually empty after the user picks options, so the browser's own check blocks submission. Add noValidate to the form and let React Hook Form validate instead.
Props
Prop
Type
Return value
Prop
Type