RHFAutocomplete
RHFAutocomplete wraps the Material UI
Autocomplete and stores
primitive values: the option string, or the valueKey property for object
options. It supports single or multiple selection, disableClearable and
freeSolo, and suits searching through large option lists.
Use RHFAutocompleteObject when you need to store the full option object.
Usage
import RHFAutocomplete, { RHFAutocompleteProps } from '@nish1896/rhf-mui-components/mui/autocomplete';import { useForm } from 'react-hook-form';
type FormValues = {
color: string | null;
};
const { control, handleSubmit } = useForm<FormValues>({
defaultValues: { color: null }
});
<form onSubmit={handleSubmit(values => console.log(values))}>
<RHFAutocomplete
fieldName="color"
control={control}
options={['Red', 'Green', 'Blue']}
registerOptions={{ required: 'Please pick a colour' }}
/>
</form>A single select stores a string, or null when nothing is selected, and
multiple stores a string[]. A value that doesn't match any option isn't
displayed, unless freeSolo is on.
onValueChange receives { newValue, selectedOption, event, reason, details }.
newValue is the normalized value that is stored, and selectedOption is the
raw Material UI selection: the option object, or the typed string with
freeSolo. event, reason (such as selectOption, removeOption, clear
or createOption) and details come straight from the Material UI change
handler.
The label, helper text and error props work as described in RHFTextField.
With an array of objects
Options can also be objects. In this case, both labelKey and valueKey are
required. labelKey is the property used as each option's visible label, and
valueKey is the property used as its value. The stored value is the valueKey
property of the selected option, not the whole object.
<RHFAutocomplete
fieldName="country"
control={control}
options={countryList} // imported from RHFCountrySelect
labelKey="name"
valueKey="iso3"
/>When using an array of objects for options, both labelKey and valueKey
are required. If either is missing, an error will be thrown.
To store the whole object, use RHFAutocompleteObject instead.
Multiple selection
Set multiple to store a string[] and show each selection as a chip. The menu
stays open while the user picks, whereas a single select closes after a choice.
While the field is not focused, only the first limitTags chips (default 2)
are shown, followed by a "+N More" chip. limitTags={-1} shows all of them,
and getLimitTagsText receives the number of hidden chips and returns your own
text. ChipProps customizes the chips.
type FormValues = {
skills: string[];
};
const { control } = useForm<FormValues>({
defaultValues: { skills: [] }
});
<RHFAutocomplete
fieldName="skills"
control={control}
options={['React', 'Vue', 'Angular', 'Svelte', 'Solid']}
multiple
limitTags={3}
getLimitTagsText={hiddenCount => `+${hiddenCount} skills`}
ChipProps={{ color: 'primary', size: 'small' }}
registerOptions={{
validate: value => value.length > 0 || 'Pick at least one skill'
}}
/>If you need checkboxes and a "Select All" row, use RHFMultiAutocomplete.
Free text entry
freeSolo lets the user enter a value that isn't in options. The typed string
is stored as it is. autoSelect defaults to true with freeSolo, so text
typed in the field is committed when it loses focus. Pass autoSelect={false}
to require Enter. With multiple, each typed value becomes its own chip.
<RHFAutocomplete
fieldName="city"
control={control}
options={['Delhi', 'Mumbai', 'Pune']}
freeSolo
/>When using freeSolo with object-based options, custom renderers such as
renderValue, renderTags, or renderOption should account for both option
objects and user-entered string values. A common approach is:
typeof value === 'string'to distinguish free-form input from predefined option objects.
Clearing the value
A clear button is shown once there is a value. disableClearable removes it, so
the stored value is never null. Give the field an initial value in that case.
const { control } = useForm<{ color: string }>({
defaultValues: { color: 'Red' }
});
<RHFAutocomplete
fieldName="color"
control={control}
options={['Red', 'Green', 'Blue']}
disableClearable
/>Loading state
Set loading while the options are being fetched. A small spinner appears at
the end of the input, and when there are no options yet, the popup shows the
loading text (loadingText, Loading… by default) instead of "No options".
circularProgressProps customizes the spinner, which is 20px by default.
<RHFAutocomplete
fieldName="user"
control={control}
options={users}
loading={isFetchingUsers}
circularProgressProps={{ size: 16 }}
/>Customizing the input
textFieldProps is forwarded to the underlying TextField, for example a
placeholder, variant or size. autoHighlight is true by default, which
differs from Material UI, so the first option is highlighted as the user types
and Enter selects it. Pass autoHighlight={false} to turn that off.
<RHFAutocomplete
fieldName="color"
control={control}
options={['Red', 'Green', 'Blue']}
autoHighlight={false}
textFieldProps={{ placeholder: 'Pick a colour', size: 'small' }}
/>Handling value changes
onValueChange runs after the new value has been stored in the form. It
receives { newValue, selectedOption, event, reason, details }; reason is one
of selectOption, removeOption, clear or createOption:
<RHFAutocomplete
fieldName="city"
control={control}
options={['Delhi', 'Mumbai', 'Pune']}
onValueChange={({ newValue, selectedOption, event, reason, details }) => {
if (reason === 'clear') {
resetSuggestions();
} else {
trackSelection(newValue);
}
}}
/>Use customOnChange when you need to change what gets stored. It replaces the
default handling, so you must call rhfOnChange yourself with the value to
store. This example limits a multiple select to five values: onValueChange is
not called when customOnChange is used.
<RHFAutocomplete
fieldName="skills"
control={control}
options={['React', 'Vue', 'Angular', 'Svelte', 'Solid', 'Qwik']}
multiple
customOnChange={({ rhfOnChange, newValue, selectedOption, event, reason, details }) => {
if (newValue.length <= 5) {
rhfOnChange(newValue);
}
}}
/>Wrapping the component
You can extend or reuse the RHFAutocomplete component by creating your own
wrapper component.
/**
* The below code snippet illustrates how to create a reusable styled Autocomplete
* component using RHFAutocomplete, which can be used throughout the application.
*
* A similar approach can be taken to create reusable styled components for:
* - RHFAutocompleteObject
* - RHFMultiAutocomplete
* - RHFMultiAutocompleteObject
*/
import { type FieldValues } from 'react-hook-form';
import RHFAutocomplete, {
type RHFAutocompleteProps
} from '@nish1896/rhf-mui-components/mui/autocomplete';
import type { StrObjOption } from '@nish1896/rhf-mui-components/types';
type StyledAutocompleteProps<
T extends FieldValues,
Option extends StrObjOption = StrObjOption,
LabelKey extends Extract<keyof Option, string> = Extract<keyof Option, string>,
ValueKey extends Extract<keyof Option, string> = Extract<keyof Option, string>,
DisableClearable extends boolean = false,
FreeSolo extends boolean = false
> = Omit<RHFAutocompleteProps<T, Option, LabelKey, ValueKey, true, DisableClearable, FreeSolo>, 'multiple'>;
const StyledAutocomplete = <
T extends FieldValues,
Option extends StrObjOption = StrObjOption,
LabelKey extends Extract<keyof Option, string> = Extract<keyof Option, string>,
ValueKey extends Extract<keyof Option, string> = Extract<keyof Option, string>,
DisableClearable extends boolean = false,
FreeSolo extends boolean = false
>({
...rest
}: StyledAutocompleteProps<T, Option, LabelKey, ValueKey, DisableClearable, FreeSolo>) => {
return (
<RHFAutocomplete
formHelperTextProps={{
sx: { fontColor: theme => theme.palette.info.main }
}}
multiple
{...rest}
/>
);
};
export default StyledAutocomplete;
Examples
API
The RHFAutocompleteProps interface extends
AutocompleteProps and accepts
the following additional props. Props marked with * are required.
| Name | Type | Description |
|---|---|---|
fieldName* | string | Name of the field registered with React Hook Form. This prop is required for all components. |
control* | UseFormControl | |
registerOptions | RegisterOptions | React Hook Form validation rules. Useful when not using a schema validation library such as Yup or Joi. |
options* | string[] / object[] | An array with string or object values. Make sure to pass labelKey and valueKey when options is an array of objects. |
labelKey | string | Property name used as the visible label for each option. Required when options is an array of objects. |
valueKey | string | Property name used as the stored value for each option. Required when options is an array of objects. |
multiple | boolean | Allows multiple values to be selected. |
freeSolo | boolean | Allows users to enter values that are not present in the autocomplete options. Supported from v4 onwards. |
customOnChange | ({ rhfOnChange, newValue, selectedOption, event, reason, details }) => void | Override the default onChange behavior of the autocomplete. |
onValueChange | ({ newValue, selectedOption, event, reason, details }) => void | Returns the latest value of the field in newValue parameter. The last selected option can be obtained from selectedOption. |
label | ReactNode | The text to render in the FormLabel component. By default, the value of fieldName is transformed (e.g., "firstName" to "First Name") using the fieldNameToLabel function. |
showLabelAboveFormField | boolean | Render form label above the form field in FormLabel component. |
formLabelProps | FormLabelProps | FormLabelProps to customise FormLabel component for a field. Multiple fields can be configured using the ConfigProvider component. |
hideLabel | boolean | Hides the FormLabel component if you don’t want to display the default form label component or prefer to render a fully custom label instead. |
required | boolean | Indicates that the field is mandatory by adding an asterisk symbol (*) to the formLabel. This visual cue helps users quickly identify required fields in the form. |
renderError | (error: FieldError) => ReactNode | Custom renderer for the React Hook Form field error. Receives the current field error and returns the content to display, such as error.message or a custom React element in the HelperText component.Added in v4.1.0. |
hideErrorMessage | boolean | A flag to prevent replacement of helper text of a field by the errorMessage when the validation is triggered. |
helperText | ReactNode | The content to display within the FormHelperText component below the field. If the field validation fails, this content will be overridden by the corresponding error message. |
formHelperTextProps | FormHelperTextProps | FormHelperTextProps to customise FormHelperText component for a field. Multiple fields can be configured using the ConfigProvider component. |
textFieldProps | TextFieldProps | Props to customise the Autocomplete Textfield. |
ChipProps | ChipProps | Props applied to the Chip component used to render selected values. |
circularProgressProps | CircularProgressProps | Props forwarded to the CircularProgress displayed in the autocomplete input when it is loading.Added in v4.3. |
customIds | { field, label, helperText, error } | Overrides the default field, label, helper text, and error IDs used for accessibility. |
Source Code
View the full implementation of this component on GitHub.

