Select Component State Management#
The Ant Design Select component is a thin wrapper around RcSelect from @rc-component/select , which owns all core internal state (open/close, searchValue, activeValue). The antd wrapper handles theming, notFoundContent resolution , and prop merging before forwarding everything to RcSelect via a spread . State management bugs almost always trace to either the application-level pattern around remote options or component lifecycle issues inside rc-overflow/rc-select when mode="multiple" with maxTagCount="responsive".
Remote Search State: The DebounceSelect Pattern#
The canonical remote-search pattern is the DebounceSelect component shown in the official demo. It manages three pieces of local state:
fetching— spinner visibilityoptions— the current fetched option listfetchRef— a counter to discard stale responses
Known stale-filter bug (issue #58733): In mode="multiple", after selecting an option, the search text is cleared from the input automatically, but onSearch is not called with an empty string. The options state is therefore stuck on the last fetched results, so reopening the dropdown shows only the previously filtered list.
The fix: add an onDropdownVisibleChange handler that re-fetches when the dropdown reopens with no search text:
onDropdownVisibleChange={(open) => {
if (open) debounceFetcher('');
}}
Also note the fetchId guard pattern : every invocation of loadOptions increments fetchRef.current and captures the current value as fetchId. If the response returns after a newer request has been issued, the stale result is silently dropped. This is the correct approach for preventing race conditions in remote search.
searchValue Clearing After Selection#
PR #55987 (closed) addressed a bug where the internal searchValue was not cleared when the dropdown had no results and notFoundContent was null/falsy. The fix added a mergedOnMouseDown handler inside InternalSelect that calls event.stopPropagation() when propagation has not already been stopped — wired into RcSelect via onMouseDown. The related issue was #55968.
PR #55933 (closed, related issue #55854) addressed the companion problem where the dropdown failed to close automatically in search mode after a selection. Both PRs modified components/select/index.tsx and components/select/style/select-input.ts.
Note: Both PRs are closed. Verify whether the fixes landed in a release by checking the CHANGELOG before depending on this behavior.
Multiple Mode: Component Recreation on Value Transitions (maxTagCount="responsive")#
When mode="multiple" and maxTagCount="responsive", rc-overflow conditionally wraps the rendered overflow node in a ResizeObserver based on whether data.length is truthy . This means the internal Input element is destroyed and recreated whenever the selected values array transitions between empty and non-empty — i.e.:
- Selecting the first option (empty → one value)
- Removing the last tag (one value → empty)
This remount is the root cause of two related symptoms:
- Cursor loss — After selecting the first option, the cursor (caret) disappears from the search input. (issue #29444, )
- onBlur not triggered on first blur — Because the input is recreated, the first click outside does not fire
onBlur; the component keeps theant-select-focusedCSS class stuck on. (issue #30325, )
The root cause was identified in rc-overflow :
const isResponsive = data.length && maxCount === RESPONSIVE; // data.length causes conditional remount
Changing this to const isResponsive = maxCount === RESPONSIVE (removing the data.length guard) prevents the conditional wrapping and eliminates the remount. A second proposed approach was re-focusing inputRef inside rc-select whenever values transition between empty and non-empty, using a useEffect with a lastValuesRef.
Status: Maintainers confirmed this is resolved in antd ≥ 6.4.5 / 6.5.0. If you are on an older version, the temporary workaround is to manually remove ant-select-focused via onDropdownVisibleChange and onClear.
Key Files and References#
| Resource | Notes |
|---|---|
components/select/index.tsx | Antd Select wrapper; notFoundContent resolution at lines 285–292 , prop spread to RcSelect at line 450 |
components/select/demo/select-users.tsx | Official remote-search demo (DebounceSelect); stale-filter bug and fetch-race guard pattern |
| PR #55987 | fix(Select): automatically clear searchValue — onMouseDown propagation stop, related to issue #55968 |
| PR #55933 | fix(Select): In search mode, the select dropdown automatically closes — related to issue #55854 |
| Issue #30325 | maxTagCount="responsive" causes onBlur not triggered at first time — resolved ≥ v6.4.5 |
| Issue #29444 | maxTagCount="responsive" causes lost cursor — resolved ≥ v6.5.0 |
| Issue #58733 | Remote search on multiple select: stale filter state after selection (demo-level bug) |