JedWatson / react-select

The Select Component for React.js
https://react-select.com/
MIT License
27.61k stars 4.12k forks source link

How to make react-select required in a form? #3140

Closed cnamazone closed 3 years ago

cnamazone commented 6 years ago

I need to make react-select required in a form,

Thebarda commented 6 years ago

Required in prop types of your component form ?

Thebarda commented 6 years ago

@cnamazone I guess you can import Select from react-select inside your form container component then pass Select as props.

Then, check the prop type.

But why can't you directly import Select in your form ?

pipzpadilla commented 5 years ago

i have the same issue, i need to make my react-select to be required, ex: birth date with year, month ,day dropdown

IanVS commented 5 years ago

This might be a dupe of https://github.com/JedWatson/react-select/issues/1453

springboardStudent commented 5 years ago

for security reasons if you cannot validate data then you risk your applications being compromised.

gwyneplaine commented 5 years ago

This is on the roadmap for our team in the upcoming set of releases. It's a non-trivial body of work, so we're taking our time to make sure we get it right. Thanks for your patience and understanding everyone. ๐Ÿ™

dehghani-mehdi commented 5 years ago

Any update here?

Rutulpatel7077 commented 5 years ago

+1

AlphaH7 commented 5 years ago

Any updates?

Rutulpatel7077 commented 5 years ago

Is this repo still getting maintained ? Just curious, should I make PR ?

claudiuapetrei commented 5 years ago

@Rutulpatel7077 @gwyneplaine Managed to do this with custom input component and just passed a flag into props, then got it from props.selectProps.selectProps. It does not seem to support this but it's flexible enough to do kinda everything you want. My app is in clojurescript (bit of interop with js) don't know how helpful a code example would be.

Rutulpatel7077 commented 5 years ago

I think the simplest solution is to add another hidden input now. I have added simple input under react-select field.

 <Fragment>
      <Select {...rest} options={options} filterOptions={filterOptions} />
          {!props.disabled && (
            <input
              tabIndex={-1}
              autoComplete="off"
              style={{ opacity: 0, height: 0 }}
              value={value}
              required={required}
            />
            )}
  </Fragment>

image

https://codesandbox.io/s/react-select-v2-required-input-3xvvb?fontsize=14

In some cases you do need position absolute in style

louis-atvero commented 4 years ago

Hey, so I got this asterisk to appear as desired, looks exactly like the built in one. This is for fully managed fields, so there's no form tag, I disable the form myself with JS. This is the big problem I had, and searching led me here.

I make a wrapper component and give the Select a className like "my-className" in the props, and I append " required" to the className based on a required prop. That's not classNamePrefix

Then apply this css

.my-className.required::after {
    content: "*";
    color: rgb(255, 95, 95);
    position: absolute;
    top: -5px;
    right: -10px;
  }

Like this:

Screenshot from 2019-11-18 12-15-01

clovis1122 commented 4 years ago

Any update on this?

giancarlobrusca commented 4 years ago

Any ETA on this?

AlphaH7 commented 4 years ago

Hi, i used ref to make the input field required on componentDidMount, you can try the same.

On Wed, 29 Jul 2020, 20:25 Giancarlo Brusca, notifications@github.com wrote:

Any ETA on this?

โ€” You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/JedWatson/react-select/issues/3140#issuecomment-665713970, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFKDT4CTDO3FNHEN2KACILDR6AZ6VANCNFSM4F647WEA .

m-kiruba commented 4 years ago

Hi, i used ref to make the input field required on componentDidMount, you can try the same. โ€ฆ On Wed, 29 Jul 2020, 20:25 Giancarlo Brusca, @.***> wrote: Any ETA on this? โ€” You are receiving this because you commented. Reply to this email directly, view it on GitHub <#3140 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFKDT4CTDO3FNHEN2KACILDR6AZ6VANCNFSM4F647WEA .

this.topicRef.current.select.inputRef.required = true;

Luiyit commented 4 years ago

I'm using the version 3.1.0. I couldn't access to the input ref. I created a simple Select wrapper.

import React from 'react'
import Select from 'react-select';

const SelectWrap = props => {
  const { value, required, disabled, className } = props;
  let pardeValue = value;
  if(Array.isArray(value) || typeof value === 'object')
    pardeValue = Object.keys(value).length > 0 ? value : "";

  return (
    <div className="select-wrapper-container">
      <Select {...props} className={`${className} select-wrapper`}/>
      <input 
        className="input-required" 
        type="text" 
        value={pardeValue && JSON.stringify(pardeValue)} 
        tabIndex={-1}
        autoComplete="off" 
        required={required} 
        disabled={disabled} 
      />
    </div>
  )
}

export default SelectWrap

The style can be more simple, but I want to make my hidden input the same size of the select.

.select-wrapper-container{
  position: relative;
  .select-wrapper{
    position: relative;
    z-index: 1;
  }
  .input-required{
    position: absolute;
    border: 0;
    color: transparent;
    background-color: transparent;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 0;
  }
}
Intelliflex commented 4 years ago

The best way I found is to create a transparent input field that will be queried via javascript standard checkValidity. This should have absolute positioning and 100% width & height. You can then bind a listener to the input field for the invalid event created by checkValidity

Here is the code I use. There are alterations for use of value field as well as some styling (for MDB inputs) , but you can just change the classes of input to match your own styles libraries. In this manner your validation styling will be the same as your existing form inputs.

Hopes this helps someone.

    /**************************************************************************************
 *** Select - New Select Control Using react-select (to stop stupid probs with MDB) ***
 **************************************************************************************/
// Use This progressively instead of InputSelect
/* Differences from native ReactSelect 
    Validation - Applies transparent input overlay that works with form checkValidity()
    value: This is the record.field value not an object {label: x, value: y} as for react-select
    grouped: Explicitly set grouped options when set true
    objValue: Works the same as react-select value object
*/
// Note: value property works differently do react-select , use ObjValue to work same as react-select
export const Select = (props) => {
  let { id, options, cols, value, objValue, label, grouped, ...o } = props
  id = id ? id : 'react-select'
  const [selected, setSelected] = useState(value)
  const [invalid, setInvalid] = useState(false)

  //DEFAULTS
  if (!grouped) grouped = false

  //--------------------------
  // VALIDATION EVENT HANDLERS
  //--------------------------
  useEffect(() => {
    //ADD EVENT HANDLER FOR FOR VALIDATION
    let ele = document.getElementById(`${id}_invalid}`)
    ele.addEventListener('invalid', (e) => {
      console.log('e is ', selected, e)
      if (typeof selected === 'undefined' || selected !== null) setInvalid(true)
    })
    //ON COMPONENT EXIT - REMOVE EVENT HANDLER
    return () => {
      ele.removeEventListener('invalid', () => {
        setInvalid(false)
      })
    }
    // eslint-disable-next-line
  }, [])

  //Value property (Allows Single field assignent) - translates to object in for {label:x, value:y}
  useEffect(() => {
    let val
    if (grouped) {
      val = _.findInGroup(options, 'options', (rec) => rec.value === value)
    } else {
      val = options.find((rec) => rec.value === value)
    }
    //console.log('Selected==>', val)
    setSelected(val)
    // eslint-disable-next-line
  }, [value, options])

  //objValue Property (Emulate standard react-select value object)
  useEffect(() => {
    if (objValue) {
      setSelected(objValue)
    }
    // eslint-disable-next-line
  }, [objValue])

  //STYLING SAME AS MDB INPUT COMPONENTS
  const customStyles = {
    valueContainer: (provided, state) => ({
      ...provided,
      backgroundColor: 'aliceblue',
    }),
    dropdownIndicator: (provided, state) => ({
      ...provided,
      backgroundColor: 'aliceblue',
    }),
  }

  const handleChange = (opt, i) => {
    setSelected(opt)
    //Callback function (i is used for nested data in record)
    if (props && props.onChange) props.onChange(opt, i)
  }

  return (
    <Col cols={cols}>
      {label && <label className='tp-label text-uppercase'>{label}</label>}
      <div className='select-wrapper'>
        <ReactSelect
          styles={customStyles}
          value={selected ? selected : ''}
          options={options}
          onChange={(val, i) => handleChange(val, i)}
          isSearchable={true}
          {...o}
        />
        <input
          id={`${id}_invalid}`}
          name={`${id}_invalid}`}
          value={selected ? selected : ''}
          onChange={() => {}}
          tabIndex={-1}
          className={`form-control tp-input w-100 ${invalid ? '' : 'd-none'}`}
          autoComplete='off'
          //value={selected}
          onFocus={() => {
            setInvalid(false)
          }}
          style={{
            position: 'absolute',
            color: 'transparent',
            backgroundColor: 'transparent',
            top: 0,
            left: 0,
            width: '100%',
            height: '100%',
            zIndex: 0,
          }}
          required={true}
        />
      </div>
    </Col>
  )
}
orszaczky commented 4 years ago

serously, this has been open for 2 years? ๐Ÿ˜ฎ

Intelliflex commented 4 years ago

I worked a solution for this - if I remember on Tuesday I'll post it

Mike Thomson Intelliflex Software ๐Ÿ“ž 0431817772


From: Gabor Orszaczky notifications@github.com Sent: Friday, October 2, 2020 3:39:44 PM To: JedWatson/react-select react-select@noreply.github.com Cc: Mike Thomson mike.intelliflex@outlook.com; Comment comment@noreply.github.com Subject: Re: [JedWatson/react-select] How to make react-select required in a form? (#3140)

serously, this has been open for 2 years? ๐Ÿ˜ฎ

โ€” You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/JedWatson/react-select/issues/3140#issuecomment-702535650, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AL6F6V3DYB7TTHQZDUOMW63SIVRSBANCNFSM4F647WEA.

Intelliflex commented 4 years ago

Ok I went to post my solution and realised I had already done this in part. I also see people giving me a thumbs down for my attempt to help. You are using a free product that someone has taken the time to share and then want to be critical when others contribute to peoples problems. Go pay for a commercial licence and their support and perhaps you can feel justified. I'll be buggered if I want to help you.

AbhaysinghBhosale commented 3 years ago

any update on isRequired option in props

Methuselah96 commented 3 years ago

I've started a fork of react-select. Feel free to resubmit this issue on the fork and/or submit a PR to resolve this issue on the fork and we can get it merged and released.

EDIT: :tada: I've archived the fork now that we've got some momentum in this repo and Jed is involved again. Sorry for the disturbance!

robbienicol commented 3 years ago

this would be cool

ebonow commented 3 years ago

I would say at this point, this feature is blocked by onBlurClearInput as this will cause the default behavior of the Select to always fail the required validation. If we add this feature first, then validation could be opt-in in correlation with this prop.

The best solution I can think of is making this be a controlled input: 1) onInputChange, if action is 'focus-blur' and it is a valid option, then setInputValue back to the inputValue

2) const Input = props => <components.Input {...props} required={props.selectProps.required} />

However, this will not work for isSearchable = false though.

I am also still trying to wrap my mind around the issue of mobile causing the keyboard to popup even if it's not searchable because the select is still focusing on an input. I think isSearchable perhaps should receive a controlled dummySelect so that the validation rules better reflect the use case though Im not certain if that solves mobile usability.

ebonow commented 3 years ago

@Intelliflex

Ok I went to post my solution and realised I had already done this in part. I also see people giving me a thumbs down for my attempt to help. You are using a free product that someone has taken the time to share and then want to be critical when others contribute to peoples problems. Go pay for a commercial licence and their support and perhaps you can feel justified. I'll be buggered if I want to help you.

Sorry and I do not understand why so many people in the community gave you a thumbs down. It's frustrating to spend so much time helping people solve their problems without appreciation because the silver platter wasn't shiny enough. I personally have been making a solid effort to close out issues with examples and I understand in some cases it might not even be looked at. In the end though, there's always the developer with years less experience trying to get started and if I can fill that one knowledge gap, cool.

All that to say, whether you decide to share or not, I don't blame you either way. I simply appreciate you being a part of the community. We can always use more builders than critics. ๐Ÿป

ebonow commented 3 years ago

I have created a comprehensive ticket to capture the remaining open issues requesting validation and isRequired. https://github.com/JedWatson/react-select/issues/4327

If you want to be a part of shaping the way forward with this feature or are curious about the complexities holding up this feature, please hop in and contribute to the conversation.

That said, I will be closing this ticket to focus our collective efforts related to this feature in #4327

jawwadzafar commented 3 years ago

Somebody on the holy internet has solved this, until we have isRequired prop. https://codesandbox.io/s/react-select-v2-required-input-3xvvb

Intelliflex commented 3 years ago

Yes itโ€™s solved, i have a new library coming soon called bootflex. This is a bootstrap themed layout, form and context library, that will handle validation of inputs bootstrap style but with schema support (so input is as simple as with all the usual properties. It should be up on npm by start of Jan. It includes full editor features that incorporate react-hook-form.

Cheers Mike Intelliflex

Mike Thomson Intelliflex Software


From: Jawwad Zafar notifications@github.com Sent: Friday, December 18, 2020 7:26:10 PM To: JedWatson/react-select react-select@noreply.github.com Cc: Mike Thomson mike.intelliflex@outlook.com; Mention mention@noreply.github.com Subject: Re: [JedWatson/react-select] How to make react-select required in a form? (#3140)

Somebody on the holy internet has solved this, until we have isRequired prop. https://codesandbox.io/s/react-select-v2-required-input-3xvvb

โ€” You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/JedWatson/react-select/issues/3140#issuecomment-747969143, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AL6F6V5SDD7V2AFH3CLFEDLSVMN3FANCNFSM4F647WEA.

rodrigoAbril commented 3 years ago

Somebody on the holy internet has solved this, until we have isRequired prop. https://codesandbox.io/s/react-select-v2-required-input-3xvvb

Bless his GitHub account!!!! ๐Ÿ˜ข Sorry for you if you want isMulti as it wont work

ebonow commented 3 years ago

Bless his GitHub account!!!! ๐Ÿ˜ข Sorry for you if you want isMulti as it wont work

Don't worry. I'm sure any of the 27-57 people who downvoted Intelliflex will post a solution for the community any day now... ๐Ÿ™„

Sarcasm aside, I know at least one other collaborator had began some work on this and I started a WIP to see how this could be resolved as well.

I would suspect this would be able to be done for isMulti if a visually hidden input was added to the ValueContainer which changed its value as the onChange was fired. I would like to get to this at some point, but likely a majority of the focus will be on closing out a11y issues, resolving issues related to menu behavior, and working on an unstyled version of react-select.

Form managers such as react-hook-form and formik handle this programmatically with much better logic separation for validation, but for simple cases, I agree that it would be nice to have this "out-of-the-box".

danielfonda commented 2 years ago

Somebody on the holy internet has solved this, until we have isRequired prop. https://codesandbox.io/s/react-select-v2-required-input-3xvvb

Give this man a cookie!

winayazarkasih commented 2 years ago

Thank You @Rutulpatel7077 Your solution solve my issue

RUPAAK commented 2 years ago

Still no updates...noice!

albydeca commented 2 years ago

such a fix should be included in an official release

jezmck commented 2 years ago

With react-hook-form, the following is working for me.

<Controller
  control={control}          // from useForm()
  name="countryCode"
  rules={{ required: true }} // ๐Ÿ‘ˆ This bit!
  render={({ field }) => (
    <Select
      options={countryCodes}
      onChange={(val: any) => field.onChange(val.value)}
    />
  )}
/>
WickyNilliams commented 2 years ago

The required attribute is used (among other things) to communicate to screen readers that the field must be filled in.

Therefore using react-hook-form's validation to require the value at validation time is not the same as adding the required attribute, unfortunately. Validation can only do this after submit/change, which is not great in terms of usability. It is better if this is communicated in advance, when first encountering the field.

Similarly, hidden inputs are not a solution, since the input a user will interact with will not be announced as required.

I understand that perhaps the native required attribute will cause issues with form validation if you're clearing inputs. I would therefore suggest mapping a required prop to aria-required="true" attribute on the input. This will fix the accessibility issue whilst also avoiding triggering native form validation.

This is a critical accessibility issue, and it is sad that it has not been fixed in 4 years

ThaNico commented 1 year ago

I've used the solution of the codesandbox link a few replies above But in my case I'm using the chakra react select wrapper from csandman (and functional components) I wanted not only to have the focus but also the "invalid" red border, not the focus border It's ugly and maybe there something easier but I'll put some stuff below that might be useful for others

First to make it work for functional component, I have :

Then for the red border, I want to use the isInvalid prop from chakra react select So I added a new state/bool + the isInvalid prop on the select And now when the input's onFocus is called, I set the isInvalid (also reset it back onChange)
Finally I have to blur to exit focus and have the red border shown (I needed to still call focus to auto scroll to field)

I wrote this fast but basically my input onFocus contains this ugly baby

selectRef.current.focus();
    setIsInvalid(true);
    selectRef.current.blur();
michaelmccomiskey commented 1 year ago

Using v5 of react-select, I am able to pass the required attribute to the input by creating a custom component for the Input.

export const Input = <
    Option extends OptionType,
    IsMulti extends boolean,
>(props: InputProps<Option, IsMulti>): ReactElement => (
        <selectComponents.Input required={props.selectProps.isRequired} {...props}>
            {props.children}
        </selectComponents.Input>
    );
<ReactSelect
   components={{Input}}
   isRequired={isRequired}
   ...
/>

Screen Shot 2022-11-16 at 10 25 34 AM

isRequired needed to be added to a declaration file then passed to ReactSelect.

EDIT: use v5.6 ๐Ÿ˜ƒ https://github.com/JedWatson/react-select/issues/3140#issuecomment-1387215825

thpun commented 1 year ago

Using v5 of react-select, I am able to pass the required attribute to the input by creating a custom component for the Input.

export const Input = <
  Option extends OptionType,
  IsMulti extends boolean,
>(props: InputProps<Option, IsMulti>): ReactElement => (
      <selectComponents.Input required={props.selectProps.isRequired} {...props}>
          {props.children}
      </selectComponents.Input>
  );
<ReactSelect
   components={{Input}}
   isRequired={isRequired}
   ...
/>

Screen Shot 2022-11-16 at 10 25 34 AM

isRequired needed to be added to a declaration file then passed to ReactSelect.

I believe selectComponents refers to components in react-select exports.

Following @michaelmccomiskey 's approach of customizing component, required prop did pass down to input. Since i'm lazy, i didnt add extra prop but reuse the required prop in Select props. But then, i encountered input always triggered the "Please fill out this field" when submit even if selected sth (regardless of isMulti). That's because the selected value was put as div and not set in input. I expect that if value is set in Select, the required check in input should pass. Therefore, i change a bit on the required condition:

import Select, {components, InputProps} from 'react-select';

const Input = <Option, IsMulti extends boolean>(props: InputProps<Option, IsMulti>) => {
    return <components.Input {...props} required={ props.selectProps.required && !props.hasValue }>
        {props.children}
    </components.Input>
};

...
export default () => {
    return (
        ...
        <Select 
            components={{Input}}
            required={true}
        />
        ...
    )
}
aldarsuresh12 commented 1 year ago

Somebody on the holy internet has solved this, until we have isRequired prop. https://codesandbox.io/s/react-select-v2-required-input-3xvvb

but you cannot use this in same page with diffrent option type.. Do you have solution for it..?

Rall3n commented 1 year ago

With version 5.6 came required validation in form of the required prop. It currently requires the name prop to work, but #5536 will make the name prop optional (synonymous to default HTML form elements).

For older versions I recommend following approach:

declare module 'react-select/dist/declarations/src/Select' {
  export interface Props<
    Option,
    IsMulti extends boolean,
    Group extends GroupBase<Option>
  > {
    required?: boolean;
  }
}

...

const RequiredInput = ({ onFocus }: { onFocus: FocusEventHandler<HTMLInputElement> }) => (<input
  type="text"
  required
  aria-hidden="true"
  tabIndex={-1}
  style={{
    opacity: 0,
    pointerEvents: 'none',
    position: 'absolute',
    bottom: 0,
    left: 0,
    right: 0,
    width: '100%'
  }}
  onFocus={onFocus}
/>);

const RequiredControl = <Option, isMulti extends boolean>(props: ControlProps<Option, isMulti>) => {
  const { selectProps, hasValue } = props;

  return (<React.Fragment>
    <components.Control {...props} />
    {(selectProps.required && !selectProps.isDisabled && !hasValue) && <RequiredInput onFocus={(e) => {
      e.preventDefault();
      e.stopPropagation();

      document.querySelector<HTMLInputElement>(`#${selectProps.inputId}`)?.focus();
    }} />}
  </React.Fragment>);
};

<Select
  components={{
    Control: RequiredControl
  }}
  inputId="test"
  required
 />
juanbomfim22 commented 1 year ago

So long story short, from 5.6 on, if you want to use required, combine it with a name attribute in the Select. For example: <Select name="foo" required ... />

As seen in this example.

As you run, notice that clearing the Select sets its value attribute to null. However, at the same time, it displays the "Please fill out this field", which may be undesirable.

pipe2k27 commented 1 year ago

So long story short, from 5.6 on, if you want to use required, add a name field in the select. Example: <Select name="foo" required ... />

This is actually working! thank you so much!

tobiasriemenschneider commented 1 year ago

So long story short, from 5.6 on, if you want to use required, add a name field in the select. Example: <Select name="foo" required ... />

This does not seem to work with CreatableSelect. Any ideas?

Lubos-source commented 10 months ago

I solved similar problem with:

In my return where I have some form with Multi Select input:

.....
.....
      <Select
            isMulti
            closeMenuOnSelect={false}
            className={error ? 'has-error' : ''}
            options={options}
            value={selectedOptions}
            onChange={setSelectedOptions}
        />
          {error && <p className="error-message" style={{color:'red'}}>{error}</p>}
.....
.....

On some handle function before Send form:

if (selectedOptions.length === 0) {
      setError('You must choose at least one option!');
      return;
    }
    // Reset error
    setError(null);

And of course at the top you need to define State for storing:

const [error, setError] = useState(null); 

I hope this helps someone with similar problems

ahmadjarafat commented 4 months ago

Anyone has found a good way to do this with CreatableSelect?