select
select copied to clipboard
`<Select>` component `<form>` compatability
Description
Currently <Select>
component is not fully <form>
compatible, which means when you submit a <Form>
or <form>
the data from the <Select>
is not included in the form submission.
How to Reproduce Bug
Submit a form which contain's <Select>
(see video below or see codesandbox here)
- observe that form submission does not update the URL
- observe that no data is being sent to the backend
Motivation For Changes
1. HTML <form>
compatibility
- Being
<form>
compliant means that people have the additional option of using Ant's<Select>
in a similar way to using a standard<select>
without losing the great UX/UI that<Select>
offers (for example using<Select showSearch>
is awesome!)
2. Many of Ant design's existing form-related components are already <form>
compliant
-
<Input>
,<InputNumber>
and<Mentions>
are already<form>
compliant - codesandbox testing
<form>
compliance of components above https://codesandbox.io/s/draft1-testing-ant-form-compatability-forked-z35rhu?file=/app/routes/examples/checkbox-component.tsx
- Removes the need for a user of Ant Design to manually add hidden input fields . This is the same issue Tailwind Headless UI had but solved in this pull request
Proposition of Changes
The proposed changes below are backwards compatible:
-
allow user to pass
name
prop to<Select>
to achieve feature compliance with regular<select>
which does allowname
prop (Ex:<select name="vehicle">
). -
When a user passes
name
prop to<Select>
generate a hidden input (<input type="hidden" name={selectProps.name}>
) and when the user selects the value from the list, addvalue
attribute to the hidden input and set it to the selected value (<input type="hidden" name={selectProps.name} value={selected_value}>
. Inspiration for this implementation comes from Tailwind's Headless UI react library (Github Pull Request)
For single item selection (fake code for demonstrative purpose)
<Select showSearch style={{ width: 300 }} name="job_title">
<Select.Option value="engineer">engineer</Select.Option>
<Select.Option value="teacher">teacher</Select.Option>
// This hidden input would get generated from <Select> when a `name` prop is provided
// <input type="hidden" name={select.props.name} value={the_selected_value}>
</Select>
For multi selection (fake code for demonstrative purpose) mode=tags | multiple
<Select showSearch style={{ width: 300 }} name="job_title">
<Select.Option value="engineer">engineer</Select.Option>
<Select.Option value="teacher">teacher</Select.Option>
// Any time a new item is selected a new hidden input is generated from <Select> when a `name` prop is provided
// <input type="hidden" name={select.props.name} value={the_selected_value}>
// <input type="hidden" name={select.props.name} value={the_selected_value}>
</Select>
Summary
To solve this, <Select>
needs name
prop support & it needs to generate a hidden <input>
element for the selected value
References
Documentation for <form>
comptability
-
<form>
compatibility example Github Pull request for tailwind React UI library + example tests - documentation for `
Related Issues
- https://github.com/react-component/select/issues/790
- https://github.com/react-component/select/issues/791
native form compatibility would be a big win!
The more compatibility the better. I didn't realize there wasn't native <form>
compatibility until this issue was raised.
Encountered this issue a couple weeks ago and couldn't find any work around. Adding this feature would be greatly appreciated!
Thanks for documenting all this @cliffordfajardo The proposed changes would also help out a lot with e2e testing.
The way the current Select
component is generated in the DOM, makes it tricker to select the Select
component and verify values in e2e testing.
Example
React Code
// AntDesign Select component
<Form.Item label="AntDesign Selector" name="Ant-Selector-FormItem">
<Select data-testid="Ant-Selector">
<Select.Option value="YES">YES</Select.Option>;
<Select.Option value="NO">NO</Select.Option>;
</Select>
</Form.Item>
DOM
// AntDesign Select component Generated in DOM
<div class="ant-select ant-select-single ant-select-show-arrow" data-testid="Ant-Selector">
<div class="ant-select-selector">
<span class="ant-select-selection-search">
<input type="search" id="Ant-Selector-FormItem" autocomplete="off" class="ant-select-selection-search-input" role="combobox" aria-haspopup="listbox" aria-owns="Ant-Selector_list" aria-autocomplete="list" aria-controls="Ant-Selector_list" aria-activedescendant="Ant-Selector_list_0" readonly="" unselectable="on" value="" style="opacity: 0;">
</span>
<span class="ant-select-selection-item" title="YES">YES</span>
</div>
<span class="ant-select-arrow" unselectable="on" aria-hidden="true" style="user-select: none;">
<span role="img" aria-label="down" class="anticon anticon-down ant-select-suffix">
<svg viewBox="64 64 896 896" focusable="false" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true">
<path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path>
</svg>
</span>
</span>
</div>
e2e Testing using Playwright
// e2e Test for Selector component
test('Get AntDesign Selector value', async ({ page }) => {
// When clicking on a Selector component in AntDesign, the value is not stored in the input element
// AntDesign creates a new span element, that stores/renders the selected value
// We need to check this span to ensure the value is updated
const AntSelectorValue = page.locator(
'[data-testid="Ant-Selector"] .ant-select-selector>span.ant-select-selection-item',
);
// Ideally we would want to use `.inputValue()` instead of `.innerText()`,
// but since our `Select` value is stored in a `span` we can NOT use `.inputValue()`
expect(await AntSelectorValue.innerText()).toBe('YES');
expect(await AntSelectorValue.innerText()).not.toBe('NO');
});