Skip to content
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

Input required and validation #4327

Open
ebonow opened this issue Dec 12, 2020 · 15 comments
Open

Input required and validation #4327

ebonow opened this issue Dec 12, 2020 · 15 comments
Assignees

Comments

@ebonow
Copy link
Collaborator

ebonow commented Dec 12, 2020

Creating this as a round up of existing open validation issues as of now. Hoping to create some kind of proposed solution and seeking feedback before creating a PR though others are welcome to try as well so long as we all know the challenges and impact of solving for this.

Use-case:

As a developer working within in a form, I would like to apply native html validation to my react-select component.

Duplicates:

#2751 - Required attribute should be passed down...
#3625 - Using Required attribute
#1453 - Add validation support
#4416 - Obtaining focus from the hidden input inside react-select
#3140 - How to make react-select required in a form?
#4450 - How to make reactselect get focus when required and empty

Challenges

1. Single Input

  • Currently default behavior of react-select is to clear inputValue onChange event so validation on this input would by default always be missing a value, so applied validation to this input is already not-out-of-the-box easy to implement

Possible proposal: Introduce a visibly hidden text input which renders the selected value

2. Multi Input

  • What kind of validation rules should be applied? How would this be implemented?

Possible proposal: Introduce a visibly hidden text/select input which concatenates all of the values together and apply a multiple attribute

3. isSearchable=false

  • Currently a DummyInput is used for focusing the content to replicate the focus and blur functionality currently built-in

Possible proposal: Introduce a visibly hidden select input. Apply multiple attribute if it is a Multi Input.

4. Visibly hidden input

Notes: This visually hidden element cannot be readonly, disabled, have style display: none, and would likely have tabindex="-1" to ensure it does not interfere with focus order.

Also currently (and curiously), the name prop is passed to a generated "FormField". My proposition would be to rewrite this formally as a component which also serves the benefit of decomposing Select.js.

5. Styling since anything other than a single searchable Select requires a visibly hidden input (type text or select or anything else a user suggests), then how would styling this element be possible?

Possible proposal:

  • Assuming above proposals, identify new/existing component to be used for validity
  • On mount of validator component, call element.addEventListener('invalid', handleInvalid)
  • Allow method handleInvalid to set new internal state isInvalid
  • Add internal state variable isValid and expose to other components (to style borders, colors, icons, etc)
  • Create new style component which would apply styles directly to the invalid element
  • Apply BEM modifier --is-invalid to this element to be specified in CSS (though :invalid is always available to the user as well)
  • On unmount of validator component, call element.removeEventListener('invalid', handleInvalid)

6. Breaking changes

Would changing the behavior of the FormField be a breaking change? I suppose it is very possible depending on test suites and formalizing this as a component could have other impacts.

Most everything seems additive especially since adding validation would likely be additive, however, due to the nature of this application, there exists the possibility that either required or isRequired could both already be pre-existing props so it is possible

There is slight possibility of introducing conflicting css names. Introducing InvalidInput as a stylable component which is applied as classNamePrefix__invalid-input could help avoid these collisions.

Perhaps greater likelihood is introducing css to apply to containers. It's possible classNamePrefix__control--is-invalid is already used, but I also believe it should be discouraged from applying internal naming conventions.

Maybe, we consider adding another className to the control styled element called classNamePrefix__validated-control and styles can cascade from classNamePrefix__validated-control--is-invalid to avoid naming conflicts.

That said, any feedback? If the changes are breaking then we would want to target version 4 rather than 3.2, but wanted to get community buy-in to better understand how to solve this issue given the flexibility and current functionality of react-select.

@karimdaghari
Copy link

As far as I'm concerned, I don't think that this is much of an issue. I think this should be left for the dev to solve and keep it out of react-select' scope.

For anyone wondering how I solved this "issue":

  1. Create a wrapper Select component around react-select
  2. (I'm using RHF for managing forms) add a control and a rules prop (to pass down to react-select)
  3. Technically speaking, that already does the job very well, visually speaking, it's not there.
  4. Add an error prop to detect errors (again, using RHF here) and apply certain css conditionally

The code in question:

interface CustomSelectProps extends ReactSelectProps, SharedSelectProps {
  native: false;
  control: Control<any>;
  rules: RegisterOptions;
  /**
   * The error object
   */
  error?: unknown;
  /**
   * The associated error message
   */
  errorMessage?: string;
}

// ...

<Controller
      name={name ?? ""}
      control={control}
      rules={rules}
      defaultValue={defaultValue}
      as={
        <ReactSelect
          {...props}
          id={normalizedId}
          instanceId={normalizedId}
          className={cn({
            "rounded-md shadow-md": true,
            "border-gray-200 ": !error,
            "border-red-500": error
          })}
        />
      }
    />

@ebonow
Copy link
Collaborator Author

ebonow commented Dec 13, 2020

In some ways I agree and I do love RHF, but in other ways it feels problematic to tell users to adopt an entire form management library or write your own validation wrapper when there is already built-in native support input and select DOM elements.

If react-select is going to position itself as a react based replacement for a select input, it should also support native validation or at least enable its users to do so easily.

@jawwadzafar
Copy link

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

@ebonow
Copy link
Collaborator Author

ebonow commented Feb 1, 2021

One of the ideas I started thinking about was playing around with the idea of using Constraint Validation by applying a custom validation to the input.

The idea is that the required/validation rules would exist on the hidden input, and then by passing a ref to that hidden field, it should be possible to pass the custom validity of the hidden field to the input... at least in theory.

This would eliminate the need to add another input to the page and also should play nice with form managers like React Hook Form, Formik, etc.. as it would allow the validation to naturally flow to the named field which is then passed to the input.

@Ha0Yan
Copy link

Ha0Yan commented Aug 6, 2021

any updates?

@dlsso
Copy link

dlsso commented Mar 17, 2022

Hi, you mentioned this was a high priority over a year ago but I don't see anything in progress. Is this going to happen?

@mein-beer-hu
Copy link

2022 and we are still here from 2017 😄 , Folks, have you all thought about implementing this?

@emrysal
Copy link

emrysal commented Apr 8, 2022

I fully agree with @ebonow that having to use react-hook-form to power the errors as a workaround is undesirable, definitely to tell your users as such.

In my usecase we actually already use react-select in conjunction with react-hook-form, but for our form inputs we use the default browser behaviour for validation, this means all of our inputs are great and easy to be validated, but on react-select (and therefore the select component we use) is not that trivial.

@ccummings-iddw
Copy link

ccummings-iddw commented Apr 11, 2022

For those of you working with typescript / functional components, here is a modified version of the solution post above:

/** react-select-wrapper.less */

.react-select-wrapper {
    position: relative;

    .hidden-input {
        opacity: 0;
        width: 100%;
        height: 0;
        position: absolute;
    }
}

/** react-select-wrapper.tsx */

import { useRef, useState } from "react";
import Select from "react-select";
import styles from "./react-select-wrapper.less";

type ReactSelectWrapperProps = {
    isRequired: boolean;
    value: string;
    onChange: (value: any) => void;
};

export const ReactSelectWrapper = (props: ReactSelectWrapperProps) => {
    const { isRequired } = props;
    const [state, setState] = useState({
        value: props.value
    });
    const selectRef = useRef(null);

    const onFocus = () => {
        if (selectRef.current) {
            selectRef.current.focus();
        }
    }

    const onChange = (value: any) => {
        props.onChange(value);
        setState({ value });
    };


    const getValue = () => {
        if (props.value !== undefined && props.value !== null) {
            return props.value;
        }
        return state.value || "";
    }

    return (
        <div className={styles.reactSelectWrapper}>
            <Select
                {...props}
                onChange={onChange}
                ref={selectRef}
            />
            {isRequired && (
                <input
                    tabIndex={-1}
                    autoComplete="off"
                    className={styles.hiddenInput}
                    value={getValue()}
                    onChange={() => {}}
                    onFocus={onFocus}
                    required
                />
            )}
        </div>
    );
};

@osvaldokalvaitir
Copy link

still don't have any suitable solution?

@AgataJedryszek-da
Copy link

@osvaldokalvaitir required seems to be supported as of react-select@5.6.0.

@osvaldokalvaitir
Copy link

@osvaldokalvaitir required seems to be supported as of react-select@5.6.0.

I was happy with the update, but I couldn't get it to work. You got it?

@AgataJedryszek-da
Copy link

I was happy with the update, but I couldn't get it to work. You got it?

Haven't tested it yet. That's a bummer.

@zebleck
Copy link

zebleck commented Dec 6, 2023

still a wanted feature after 7 years...

@sweinstein22
Copy link

bump here as well - I'm on 5.7 and it looks like things still aren't fixed, would love to see support for this! thanks for the work y'all put in!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests