Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for react hook form #7

Closed
zac-ng opened this issue Sep 29, 2021 · 6 comments
Closed

Support for react hook form #7

zac-ng opened this issue Sep 29, 2021 · 6 comments
Labels
Answered This question has been answered Question Further information is requested

Comments

@zac-ng
Copy link

zac-ng commented Sep 29, 2021

The component seems to break when attempting to validate the number of inputs using the register function in react hook form. Is it possible for you to add support for react hook form?

@csandman
Copy link
Owner

Can you give me an example of how you're trying to implement it? Are you using a custom controller?

@zac-ng
Copy link
Author

zac-ng commented Sep 29, 2021

I'm not using a custom controller. Here's a snippet of code I have for making sure there is at least one option selected.

<FormControl>
  <FormLabel htmlFor='food'>Food Groups</FormLabel>\n
  <FormErrorMessage>{errors.food && errors.food.message}</FormErrorMessage>
  <Select 
    id='food'
    isMulti 
    placeholder='Food Groups' 
    options={food_groups}
    {...register('food', {
      required: 'Please enter at least one food group.'
    })}
  />
</FormControl>

@csandman
Copy link
Owner

csandman commented Sep 30, 2021

If you look at the docs for the Controller component, this is what it says

React Hook Form embraces uncontrolled components and native inputs, however it's hard to avoid working with external controlled component such as React-Select, AntD and Material-UI. This wrapper component will make it easier for you to work with them.

You were never able to natively use react-select with react-hook-form and seeing as this is just a wrapper for it, it will be no different. However, its very simple to implement with a custom controller! Here's an example:

<Controller
  control={control}
  name="food"
  rules={{ required: "Please enter at least one food group." }}
  render={({
    field: { onChange, onBlur, value, name, ref },
    fieldState: { invalid, error }
  }) => (
    <FormControl id="food" isInvalid={invalid}>
      <FormLabel>Food Groups</FormLabel>

      <Select
        isMulti
        name={name}
        ref={ref}
        onChange={onChange}
        onBlur={onBlur}
        value={value}
        options={foodGroups}
        placeholder="Food Groups"
      />

      <FormErrorMessage>{error && error.message}</FormErrorMessage>
    </FormControl>
  )}
/>

And here is a fully functional example: https://codesandbox.io/s/chakra-react-select-react-hook-form-controller-v7llc?file=/example.js

Alternatively you could use the useController hook which has a very similar API except in hook form, and you could use it to make a reusable ControlledSelect component like this:

const ControlledSelect = ({ control, name, id, label, rules, ...props }) => {
  const {
    field: { onChange, onBlur, value, ref },
    fieldState: { invalid, error }
  } = useController({
    name,
    control,
    rules
  });

  return (
    <FormControl id={id} isInvalid={invalid}>
      <FormLabel>{label}</FormLabel>

      <Select
        isMulti
        name={name}
        ref={ref}
        onChange={onChange}
        onBlur={onBlur}
        value={value}
        {...props}
      />

      <FormErrorMessage>{error && error.message}</FormErrorMessage>
    </FormControl>
  );
};

And you can see a fully functional example of that here: https://codesandbox.io/s/chakra-react-select-react-hook-form-usecontroller-n8wuf?file=/example.js

P.S. If you're wrapping your Select in a FormControl (like in your example), you can pass an id directly to the FormControl to add it to the input element and associate the FormLabel with it. This lines up with the way the component normally works:

  • We've improved the accessibility of the FormControl component. Here are the changes:
    • id passed to the form control will be passed to the form input directly.
    • FormLabel will have htmlFor that points to the id of the form input.

If you choose not to do this, you'll have to use the inputId prop that is used by react-select to properly associate the text input with the label.

@zac-ng
Copy link
Author

zac-ng commented Oct 5, 2021

Awesome, thanks so much for the examples! I'll try implementing that later, thanks!

@zac-ng zac-ng closed this as completed Oct 5, 2021
@tomocrafter
Copy link

tomocrafter commented Nov 30, 2021

@csandman Can you please consider adding an option to allow onChange to pass only the value from options to be used with React Hook Form?
Edit: I'm sorry, I didn't know that onChange is triggered by react-select not this great library. I'll make function on onChange which transforms to only value.

@csandman
Copy link
Owner

csandman commented Dec 30, 2021

@tomocrafter sorry I never saw your comment! I hope you figured it out!

If not, here's an example of how you might do that with react-hook-form:

const ControlledSelect = ({
  control,
  name,
  id,
  label,
  rules,
  options,
  ...props
}) => {
  const {
    field: { onChange, onBlur, value, ref },
    fieldState: { invalid, error }
  } = useController({
    name,
    control,
    rules
  });

  return (
    <FormControl py={4} isInvalid={invalid} id={id}>
      <FormLabel>{label}</FormLabel>

      <Select
        name={name}
        ref={ref}
        onBlur={onBlur}
        options={options}
        value={
          options && value
            ? options.find((option) => option.value === value)
            : null
        }
        onChange={(option) => onChange(option.value)}
        {...props}
      />

      <FormErrorMessage>{error && error.message}</FormErrorMessage>
    </FormControl>
  );
};

I'm assuming in this case you only want a single select, because that's the main case you'd only want one value.

@csandman csandman added Answered This question has been answered Question Further information is requested labels Feb 2, 2022
Repository owner locked and limited conversation to collaborators May 5, 2022
@csandman csandman converted this issue into discussion #105 May 5, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
Answered This question has been answered Question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants