react-hook-form-mui

repository·master·Indexed 20 days ago

https://github.com/dohomi/react-hook-form-mui

A library that combines Material-UI (MUI) with react-hook-form to provide pre-configured form elements. It includes a FormContainer for easy setup and a variety of specialized components such as TextFieldElement, AutocompleteElement, CheckboxElement, and DatePickerElement. The library supports typesafe form setup via useForm, value transformation for complex MUI components, and provides a DateFnsProvider for date handling configuration.

Tokens
10.4K
Snippets
23
Records
33
Agent score
70%

What's inside react-hook-form-mui

  1. How FormContainer and form context work

    master

    The <FormContainer /> component acts as a provider that wires up the form context. This allows you to create sub-components that can access the form state using useFormContext() or useWatch() from react-hook-form.

    Note on DatePickers: If you use DatePickerElement or DateTimePickerElement, you must wrap your form with a date provider (such as Dayjs or DateFns providers) to ensure the pickers function correctly.

  2. Install react-hook-form-mui

    master

    To use react-hook-form-mui, you must install both the library and react-hook-form. Additionally, because the library utilizes MUI ecosystem components, you should install @mui/x-date-pickers and @mui/icons-material to ensure full functionality (especially for date pickers).

    Dependency Versions:

    • Versions >= 3.x use MUI v5.
    • Versions >= 6.x use @mui/x-date-pickers version 6.
    # npm
    npm install react-hook-form react-hook-form-mui
    npm install @mui/x-date-pickers @mui/icons-material
    
    # yarn
    yarn add react-hook-form react-hook-form-mui
    yarn add @mui/x-date-pickers @mui/icons-material
  3. Transform values in CheckboxElement

    master

    If your form state uses a value type that doesn't directly match a boolean checkbox (e.g., you want to store a specific string or number in the form based on whether the box is checked), use the transform prop.

    • input: Converts the value from the form state into a format the checkbox understands (typically a boolean).
    • output: Converts the change event and the new checkbox value back into the format required by the form state.
    <CheckboxElement
      name="status"
      control={control}
      label="Active Status"
      transform={{
        // If form value is 'active', checkbox is checked
        input: (val) => val === 'active',
        // If checkbox is checked, set form value to 'active', otherwise 'inactive'
        output: (event, checked) => (checked ? 'active' : 'inactive'),
      }}
    />
  4. Transform values in DatePickerElement

    master

    Because form state often uses different formats (like ISO strings or timestamps) than what a Date Picker requires (like Date objects), DatePickerElement provides a transform prop to handle this mapping.

    • input: A function that takes the value from the form and returns a PickerValidDate (e.g., Date) for the picker.
    • output: A function that takes the value from the picker and returns the format expected by your form state.

    This ensures your form data remains clean (e.g., strings) while the UI component works with the appropriate objects.

    <DatePickerElement
      name="birthday"
      control={control}
      transform={{
        // Form value (string) -> Picker value (Date)
        input: (val) => val ? new Date(val as string) : null,
        // Picker value (Date) -> Form value (string)
        output: (val) => val ? val.toISOString() : null,
      }}
    />
  5. How AutocompleteElement transforms values

    master

    By default, AutocompleteElement uses a built-in transformation logic to bridge the gap between the MUI component and react-hook-form:

    1. Input (Form $\rightarrow$ MUI): It takes the value from the form and tries to find the matching object in the options array. If matchId is enabled, it looks for an id property. If no match is found and freeSolo is enabled, it uses the value as-is.
    2. Output (MUI $\rightarrow$ Form): When a user selects an option, the component converts that object back into a form-friendly value. If matchId is enabled, it extracts the id property from the selected object. If multiple is enabled, it returns an array of IDs (or objects if matchId is false).

    You can override this behavior entirely by providing a custom transform object with input and output functions.

  6. Fixing context issues with useWatch

    master

    If you encounter issues where the React context is undefined (common when using useWatch), use the re-exported useWatch from react-hook-form-mui instead of importing it directly from react-hook-form. This ensures the hook is correctly aligned with the library's internal context.

    import {useWatch} from 'react-hook-form-mui' // instead of react-hook-form
    
    const MySubmit = () => {
        const value = useWatch('fieldName')
        return <Button disabled={!value}>Submit</Button>
    }
  7. Typesafe form setup with useForm

    master

    For more control and type safety, you can use the standard useForm hook from react-hook-form and pass the control object to the individual element components. This allows you to integrate the elements into your own <form> tag and manage submission manually via handleSubmit.

    import {useForm} from 'react-hook-form'
    import {TextFieldElement, AutocompleteElement, CheckboxElement, Button} from 'react-hook-form-mui'
    import {Stack} from '@mui/material'
    
    function Form() {
        const {control, handleSubmit} = useForm({
          defaultValues: {
            name: '',
            auto: '',
            check: false
          },
        })
        const options = [
          {id: 'one', label: 'One'},
          {id: 'two', label: 'Two'},
          {id: 'three', label: 'Three'},
        ]
        return (
            <form onSubmit={handleSubmit((data) => console.log(data))} noValidate>
              <Stack spacing={2}>
                <TextFieldElement
                  name={'name'}
                  label={'Name'}
                  control={control}
                  required
                  fullWidth
                />
                <AutocompleteElement
                  name={'auto'}
                  label={'Autocomplete'}
                  control={control}
                  options={options}
                />
                <CheckboxElement name={'check'} label={'Check'} control={control} />
                <Button type={'submit'} color={'primary'}>
                  Submit
                </Button>
              </Stack>
            </form>
        )
      }
    }
  8. Simple form setup with FormContainer

    master

    The easiest way to implement a form is using the <FormContainer /> component. It automatically handles the form context and provides an onSuccess callback that is triggered when the form is submitted successfully. You can place element components like <TextFieldElement /> inside it.

    import {FormContainer, TextFieldElement} from 'react-hook-form-mui'
    
    function Form() {
        return (
            <FormContainer
                defaultValues={{name: ''}}
                onSuccess={data => console.log(data)}
            >
                <TextFieldElement name="name" label="Name" required/>
            </FormContainer>
        )
    }
  9. Available Form Elements

    master

    The library provides several opinionated MUI-based components for react-hook-form integration:

    • AutocompleteElement
    • TextFieldElement
    • SelectElement
    • MultiSelectElement
    • RadioButtonGroup
    • CheckboxButtonGroup
    • CheckboxElement
    • SwitchElement
    • PasswordElement
    • DatePickerElement
    • DateTimePickerElement
    • SliderElement
    • ToggleButtonGroupElement
  10. Use the CheckboxElement component

    master

    The CheckboxElement component integrates a Material-UI Checkbox with react-hook-form. It handles form state, validation rules, error messaging, and value transformation. It is a typesafe component that works with your form's field values and names.

    Key features:

    • Automatic Integration: Uses useController to connect to react-hook-form via the control prop.
    • Value Transformation: Supports an input transform (to convert form state to a checkbox value) and an output transform (to convert checkbox changes back to form state).
    • Custom Error Rendering: Use parseError to provide a custom function that returns a ReactNode based on the FieldError.
    • Labeling: Supports label and labelProps for FormControlLabel configuration.
    • Helper Text: Displays a helperText string or the error message automatically when validation fails.
    import CheckboxElement from 'react-hook-form-mui/CheckboxElement';
    import { useForm } from 'react-hook-form';
    
    function MyForm() {
      const { control, handleSubmit } = useForm({
        defaultValues: {
          acceptTerms: false,
        },
      });
    
      return (
        <form onSubmit={handleSubmit(data => console.log(data))}>
          <CheckboxElement
            name="acceptTerms"
            control={control}
            label="I accept the terms and conditions"
            rules={{ required: 'You must accept the terms' }}
          />
          <button type="submit">Submit</button>
        </form>
      );
    }
  11. Use FormContainer to manage form context and submission

    master

    The FormContainer component simplifies setting up a react-hook-form context and a corresponding HTML <form> element. It can either initialize its own form state using useForm props or wrap an existing formContext provided via the formContext prop.

    Key Behaviors:

    • Automatic Context: If formContext is not provided, FormContainer calls useForm internally and provides the context to its children via FormProvider.
    • Submission Handling:
      • If onSuccess is provided (and no custom handleSubmit is passed), FormContainer automatically wraps onSuccess with react-hook-form's handleSubmit logic.
      • If a custom handleSubmit (a FormEventHandler<HTMLFormElement>) is provided, it takes precedence, and onSuccess will be ignored.
    • Form Attributes: Use the FormProps prop to pass standard HTML attributes (like className, id, etc.) to the underlying <form> element.
    • Validation: The rendered <form> element includes the noValidate attribute by default to prevent browser default validation from interfering with react-hook-form.

    Props Reference:

    • onSuccess?: A SubmitHandler<T> called when validation succeeds.
    • onError?: A SubmitErrorHandler<T> called when validation fails.
    • FormProps?: FormHTMLAttributes<HTMLFormElement> to customize the <form> element.
    • handleSubmit?: A custom FormEventHandler<HTMLFormElement> for manual submission control.
    • formContext?: An existing UseFormReturn<T> instance to be used as the form context.
    import { FormContainer } from 'react-hook-form-mui';
    
    interface MyFormData {
      firstName: string;
    }
    
    const MyForm = () => {
      return (
        <FormContainer<MyFormData>
          onSuccess={(data) => console.log('Form submitted:', data)}
          onError={(errors) => console.log('Errors:', errors)}
          FormProps={{ className: 'my-custom-form' }}
        >
          {/* Your MUI and react-hook-form-mui fields go here */}
        </FormContainer>
      );
    };
  12. Use AutocompleteElement for Material-UI Autocomplete with React Hook Form

    master

    The AutocompleteElement component integrates MUI's Autocomplete with react-hook-form. It handles the complex logic of mapping between the form's state (often just an ID or a simple value) and the full option objects required by the MUI Autocomplete component.

    Key Features

    • Automatic Controller Integration: Uses useController to manage field state, validation rules, and errors.
    • Value Transformation: Provides a transform prop to map between the form value (e.g., an ID) and the selected option object.
    • Checkbox Support: Enabling showCheckbox automatically renders a checkbox in the option list.
    • ID Matching: The matchId prop allows the component to automatically resolve values by looking for an id property on option objects.
    • Error Handling: Integrates with FormErrorProvider and supports a custom parseError function to format error messages.
    import AutocompleteElement from 'react-hook-form-mui/AutocompleteElement';
    
    // Example usage with a simple array of strings
    <AutocompleteElement
      name="category"
      control={control}
      options={['Electronics', 'Books', 'Clothing']}
      label="Select Category"
    />
    
    // Example usage with objects and ID matching
    <AutocompleteElement
      name="userId"
      control={control}
      options={[{ id: 1, label: 'Alice' }, { id: 2, label: 'Bob' }]}
      matchId
      label="User"
    />