|
11 | 11 | */
|
12 | 12 |
|
13 | 13 | import {FocusableElement, RefObject} from '@react-types/shared';
|
14 |
| -import React, {JSX, ReactNode, useCallback, useRef} from 'react'; |
| 14 | +import React, {InputHTMLAttributes, JSX, ReactNode, useCallback, useRef} from 'react'; |
15 | 15 | import {selectData} from './useSelect';
|
16 | 16 | import {SelectState} from '@react-stately/select';
|
17 | 17 | import {useFormReset} from '@react-aria/utils';
|
@@ -51,7 +51,7 @@ export interface HiddenSelectProps<T> extends AriaHiddenSelectProps {
|
51 | 51 |
|
52 | 52 | export interface AriaHiddenSelectOptions extends AriaHiddenSelectProps {
|
53 | 53 | /** A ref to the hidden `<select>` element. */
|
54 |
| - selectRef?: RefObject<HTMLSelectElement | null> |
| 54 | + selectRef?: RefObject<HTMLSelectElement | HTMLInputElement | null> |
55 | 55 | }
|
56 | 56 |
|
57 | 57 | export interface HiddenSelectAria {
|
@@ -124,7 +124,8 @@ export function useHiddenSelect<T>(props: AriaHiddenSelectOptions, state: Select
|
124 | 124 | export function HiddenSelect<T>(props: HiddenSelectProps<T>): JSX.Element | null {
|
125 | 125 | let {state, triggerRef, label, name, form, isDisabled} = props;
|
126 | 126 | let selectRef = useRef(null);
|
127 |
| - let {containerProps, selectProps} = useHiddenSelect({...props, selectRef}, state, triggerRef); |
| 127 | + let inputRef = useRef(null); |
| 128 | + let {containerProps, selectProps} = useHiddenSelect({...props, selectRef: state.collection.size <= 300 ? selectRef : inputRef}, state, triggerRef); |
128 | 129 |
|
129 | 130 | // If used in a <form>, use a hidden input so the value can be submitted to a server.
|
130 | 131 | // If the collection isn't too big, use a hidden <select> element for this so that browser
|
@@ -153,14 +154,34 @@ export function HiddenSelect<T>(props: HiddenSelectProps<T>): JSX.Element | null
|
153 | 154 | </div>
|
154 | 155 | );
|
155 | 156 | } else if (name) {
|
| 157 | + let data = selectData.get(state) || {}; |
| 158 | + let {validationBehavior} = data; |
| 159 | + |
| 160 | + let inputProps: InputHTMLAttributes<HTMLInputElement> = { |
| 161 | + type: 'hidden', |
| 162 | + autoComplete: selectProps.autoComplete, |
| 163 | + name, |
| 164 | + form, |
| 165 | + disabled: isDisabled, |
| 166 | + value: state.selectedKey ?? '' |
| 167 | + }; |
| 168 | + |
| 169 | + if (validationBehavior === 'native') { |
| 170 | + // Use a hidden <input type="text"> rather than <input type="hidden"> |
| 171 | + // so that an empty value blocks HTML form submission when the field is required. |
| 172 | + return ( |
| 173 | + <input |
| 174 | + {...inputProps} |
| 175 | + ref={inputRef} |
| 176 | + style={{display: 'none'}} |
| 177 | + type="text" |
| 178 | + required={selectProps.required} |
| 179 | + onChange={() => {/** Ignore react warning. */}} /> |
| 180 | + ); |
| 181 | + } |
| 182 | + |
156 | 183 | return (
|
157 |
| - <input |
158 |
| - type="hidden" |
159 |
| - autoComplete={selectProps.autoComplete} |
160 |
| - name={name} |
161 |
| - form={form} |
162 |
| - disabled={isDisabled} |
163 |
| - value={state.selectedKey ?? ''} /> |
| 184 | + <input {...inputProps} ref={inputRef} /> |
164 | 185 | );
|
165 | 186 | }
|
166 | 187 |
|
|
0 commit comments