Skip to Content
Piplup

rhf-adapters vs react-hook-form-mui

Compare @piplup/rhf-adapters with react-hook-form-mui for connecting MUI to React Hook Form: components, date pickers, validation, hooks and version support.

react-hook-form-mui and @piplup/rhf-adapters solve the same problem. MUI inputs are controlled components, so React Hook Form's register doesn't fit them, and both packages wrap useController in ready-made elements so you don't write a Controller for every field. They differ in what they cover, how far you can customise a field, and which React and MUI versions they support.

This page compares react-hook-form-mui 9.0 with @piplup/rhf-adapters 5.0, as of November 2026.

At a glance

react-hook-form-mui@piplup/rhf-adapters
React18 and 1919
MUIOne MUI major per release (9.x needs MUI 9)@mui/material 6 to 9, @mui/x-date-pickers 8 to 9
APIElementsAn element and a hook for every component
MUI Material inputsTextField, Select, MultiSelect, Autocomplete, Checkbox, CheckboxButtonGroup, RadioButtonGroup, Switch, Slider, ToggleButtonGroup, TextareaAutosizeTextField, Input, OutlinedInput, FilledInput, InputBase, Select, Autocomplete, Checkbox, Radio, RadioGroup, Switch, Slider, Rating
Password fieldPasswordElement, PasswordRepeatElementMuiTextFieldElement with type="password"
Labels, helper text, buttonsLabel and helper text built into each elementAlso separate elements: FormLabel, InputLabel, FormHelperText, Button, IconButton, Fab
MUI XDatePicker, MobileDatePicker, DateTimePicker, TimePicker20 components: every picker, plus DateField, TimeField, the calendars and the clocks
Picker limits such as minDate validate the formYesYes
Shorthand validation propsrequired; type="email" adds a patternrequired, min, max, minLength, maxLength, pattern; type="email" adds a pattern
Per-field messagesparseError, overwriteErrorMessages on pickersmessages, errorParser
Form-wide error formattingFormErrorProvider with onErrorFormErrorProvider with errorParser
Community inputsNonemui-chips-input, mui-color-input, mui-file-input, mui-one-time-password-input, mui-tel-input, react-number-format
Native HTML elementsNoneinput, textarea, label, button, helper text
String dates in form valuesParsed by the picker adapterDate objects only

The same field in both

A required email field in react-hook-form-mui:

import { TextFieldElement } from "react-hook-form-mui";

<TextFieldElement
  control={control}
  name="email"
  type="email"
  label="Email"
  required
  rules={{ required: "Enter your email" }}
/>;

And in @piplup/rhf-adapters:

import { MuiTextFieldElement } from "@piplup/rhf-adapters/mui-material";

<MuiTextFieldElement
  control={control}
  name="email"
  type="email"
  label="Email"
  required
  messages={{ required: "Enter your email" }}
/>;

For simple fields the two read almost the same. The differences show up at the edges.

Where they differ

Hooks for custom fields

react-hook-form-mui gives you elements and a useTransform helper. When an element's layout doesn't fit, you go back to useController and do the mapping yourself.

Every @piplup/rhf-adapters element has a hook, such as useMuiTextFieldAdapter, that returns the props the element would pass. You spread them onto your own component and keep the value mapping, the error state and the validation rules:

import InputAdornment from "@mui/material/InputAdornment";
import TextField from "@mui/material/TextField";
import { useMuiTextFieldAdapter } from "@piplup/rhf-adapters/mui-material";
import type { Control } from "react-hook-form";

type Product = { price: number | null };

function PriceField({ control }: { control: Control<Product> }) {
  const adapter = useMuiTextFieldAdapter<number | null, Product, "price", HTMLDivElement>({
    control,
    name: "price",
    type: "number",
    required: true,
    min: 0,
    composeHelperText: true,
    messages: { required: "Enter a price", min: "Price can't be negative" },
  });

  return (
    <TextField
      {...adapter}
      label="Price"
      slotProps={{
        input: { startAdornment: <InputAdornment position="start">$</InputAdornment> },
      }}
    />
  );
}

For components neither package covers, @piplup/rhf-core exports useControllerAdapter, the primitive every adapter is built on.

Select

react-hook-form-mui's SelectElement is a TextField in select mode that takes an options array, with valueKey and labelKey for object options. It renders its own helper text.

MuiSelectElement wraps MUI's Select and takes MenuItem children, the same as MUI's own examples. MUI's Select has no helper text, so the error is shown by a MuiFormHelperTextElement that reads the same field. It's more markup, but anything MUI's Select accepts works unchanged.

Date pickers

Both turn picker limits such as minDate, disablePast and shouldDisableDate into React Hook Form validation, with a default message per limit that you can override.

react-hook-form-mui covers four pickers. @piplup/rhf-adapters/mui-x-date-pickers covers 20 MUI X components: the responsive, desktop, mobile and static date, time and date-time pickers, DateField and TimeField, the date, month and year calendars, and the clocks. DateTimeField is the one value component without an adapter yet.

react-hook-form-mui also accepts a string form value and parses it with the picker's adapter. @piplup/rhf-adapters stores and expects the date object from your LocalizationProvider adapter, so convert API strings when you build defaultValues. The date picker guide shows how.

Validation props

react-hook-form-mui adds a required rule from the required prop and an email pattern for type="email"; everything else goes in rules. @piplup/rhf-adapters also reads min, max, minLength, maxLength and pattern from the element's props, so the attribute you would set on the input becomes the validation rule too. In both, rules still works for anything else.

Inputs beyond MUI Material

react-hook-form-mui covers MUI Material and four MUI X pickers. @piplup/rhf-adapters also has subpaths for mui-tel-input, mui-file-input, mui-chips-input, mui-color-input, mui-one-time-password-input, react-number-format and native HTML elements. Each subpath only needs its own peer dependency installed.

Version support

react-hook-form-mui follows MUI's major versions: upgrading MUI means upgrading it too, and version 9 needs MUI 9. It supports React 18.

@piplup/rhf-adapters 5 accepts MUI 6 through 9 in one release, so the adapters don't block a MUI upgrade. It requires React 19.

Which should you choose?

Choose react-hook-form-mui if:

  • You're on React 18.
  • You want PasswordElement, PasswordRepeatElement, ToggleButtonGroupElement or a Select driven by an options array.
  • Your form values hold dates as strings and you'd rather not convert them.

Choose @piplup/rhf-adapters if:

  • You build custom fields and want the adapter logic as a hook rather than only an element.
  • You use MUI X beyond the four main pickers, or the MUI community inputs.
  • You want min, max, minLength, maxLength and pattern props to validate.
  • You want to upgrade MUI without waiting for a matching adapter release.

Switching from react-hook-form-mui

Most elements map one to one. Import MUI Material elements from @piplup/rhf-adapters/mui-material and pickers from @piplup/rhf-adapters/mui-x-date-pickers:

react-hook-form-mui@piplup/rhf-adapters
FormContainer with onSuccessFormContainer from @piplup/rhf-core, with onSubmit
FormErrorProvider with onErrorFormErrorProvider with errorParser
TextFieldElementMuiTextFieldElement
SelectElement, MultiSelectElementMuiSelectElement with MenuItem children, multiple for several
AutocompleteElementMuiAutocompleteElement
CheckboxElement, CheckboxButtonGroupMuiCheckboxElement
RadioButtonGroupMuiRadioGroupElement
SwitchElementMuiSwitchElement
SliderElementMuiSliderElement
DatePickerElementMuiXDatePickerElement
MobileDatePickerElementMuiXMobileDatePickerElement
DateTimePickerElementMuiXDateTimePickerElement
TimePickerElementMuiXTimePickerElement
parseErrormessages for fixed text, errorParser for a function
rules={{ required: "…" }}required with messages={{ required: "…" }}, or keep rules

Two behaviours to check as you switch:

  • Checkbox values. MuiCheckboxElement stores an array of the checked boxes' values, so several checkboxes with the same name form a group. For a single yes/no box, use a transform, as shown on the MuiCheckboxElement page.
  • Imports from react-hook-form. react-hook-form-mui re-exports all of react-hook-form, so some code imports useForm from it. Import those from react-hook-form instead.

FAQ

What is the difference between react-hook-form-mui and @piplup/rhf-adapters?

Both wrap react-hook-form's useController so MUI inputs work without a Controller. react-hook-form-mui ships a set of opinionated elements in one package. @piplup/rhf-adapters ships an element and a matching hook for every supported component, covers 20 MUI X components, from every picker to the calendars and clocks, and adds adapters for the common MUI community inputs and native HTML elements.

Does @piplup/rhf-adapters work with React 18?

No. Version 5 requires React 19. react-hook-form-mui 9 supports React 18 and 19, so on React 18 it is the one to pick.

Which MUI versions do they support?

react-hook-form-mui releases one major version per MUI major: version 9 requires MUI 9. @piplup/rhf-adapters 5 supports @mui/material 6 to 9 and @mui/x-date-pickers 8 to 9 in the same release, so you can upgrade MUI without changing adapter versions.

Can I store dates as strings in the form?

react-hook-form-mui's date pickers parse a string form value through the picker adapter, so ISO strings from an API can go straight into defaultValues. @piplup/rhf-adapters expects a date object from your LocalizationProvider adapter, so convert strings when you set defaultValues and format the date when you submit.

Is there a password field with a show/hide button?

react-hook-form-mui has PasswordElement and PasswordRepeatElement. @piplup/rhf-adapters has no dedicated password element: use MuiTextFieldElement with type="password" and add the visibility toggle as an input adornment.

See also

On this page