Repository: adobe/react-spectrum
File: packages/@react-aria/select/src/HiddenSelect.tsx (TypeScript)

Code before:
          {label}
          <select {...selectProps} ref={selectRef}>
            <option />
            {[...state.collection.getKeys()].map(key => {
              let item = state.collection.getItem(key);
              if (item && item.type === 'item') {
                return (
                  <option
                    key={item.key}
                    value={item.key}>
                    {item.textValue}
                  </option>
                );
              }
            })}
          </select>
        </label>
      </div>
    );
  } else if (name) {
    let data = selectData.get(state) || {};
    // Use a hidden <input type="text"> rather than <input type="hidden">
    // so that an empty value blocks HTML form submission when the field is required.
    return (
      <input
        type="text"
        autoComplete={selectProps.autoComplete}
        name={name}
        disabled={isDisabled}
        value={state.selectedKey ?? ''}
        onChange={() => {/** Ignore react warning. */}}
        required={data.isRequired}
        hidden />
    );
  }

  return null;
}


Review comment (suggestion):
This should only be the case if `validationBehavior="native"`. If `validationBehavior="aria"`, then form submission should not be blocked. We should continue to use `type="hidden"` in that case.

Code after:
export function HiddenSelect<T>(props: HiddenSelectProps<T>): JSX.Element | null {
  let {state, triggerRef, label, name, form, isDisabled} = props;
  let selectRef = useRef(null);
  let inputRef = useRef(null);
  let {containerProps, selectProps} = useHiddenSelect({...props, selectRef: state.collection.size <= 300 ? selectRef : inputRef}, state, triggerRef);

  // If used in a <form>, use a hidden input so the value can be submitted to a server.
  // If the collection isn't too big, use a hidden <select> element for this so that browser
  // autofill will work. Otherwise, use an <input type="hidden">.
  if (state.collection.size <= 300) {
    return (
      <div {...containerProps} data-testid="hidden-select-container">
        <label>
          {label}
          <select {...selectProps} ref={selectRef}>
            <option />
            {[...state.collection.getKeys()].map(key => {
              let item = state.collection.getItem(key);
              if (item && item.type === 'item') {
                return (
                  <option
                    key={item.key}
                    value={item.key}>
                    {item.textValue}
                  </option>
                );
              }
            })}
          </select>
        </label>
      </div>
    );
  } else if (name) {
    let data = selectData.get(state) || {};
    let {validationBehavior} = data;

    let inputProps: InputHTMLAttributes<HTMLInputElement> = {
      type: 'hidden',
      autoComplete: selectProps.autoComplete,
      name,
      form,
      disabled: isDisabled,
      value: state.selectedKey ?? ''
    };

    if (validationBehavior === 'native') {
      // Use a hidden <input type="text"> rather than <input type="hidden">
      // so that an empty value blocks HTML form submission when the field is required.
      return (
        <input
          {...inputProps}