Skip to content

Select v6 searchValue is removed when options are updated with onSearch #55968

Closed

Description

@aFrameEmilio

Reproduction link

Edit on CodeSandbox

Steps to reproduce

  1. Create a Select component with showSearch enabled and async options loading
  2. Use onSearch to trigger an API call (debounced) that updates the options prop
  3. Type a search query (e.g., "test")
  4. Wait for the API response to return and update the options
import { useState } from 'react';
import { Select } from 'antd';
import { useQuery, QueryClient, QueryClientProvider } from '@tanstack/react-query';
import debounce from 'lodash-es/debounce';

const queryClient = new QueryClient();

// Simulated API call
const fetchOptions = async (query: string) => {
  await new Promise((resolve) => setTimeout(resolve, 500));
  return [
    { value: '1', label: `Result 1 for "${query}"` },
    { value: '2', label: `Result 2 for "${query}"` },
  ];
};

const AsyncSelect = () => {
  const [searchTerm, setSearchTerm] = useState('');
  const [debouncedSearchTerm, setDebouncedSearchTerm] = useState('');

  const { data: options = [], isFetching } = useQuery({
    queryKey: ['options', debouncedSearchTerm],
    queryFn: () => fetchOptions(debouncedSearchTerm),
    enabled: debouncedSearchTerm.length >= 3,
  });

  const debouncedSetSearch = debounce((value: string) => {
    setDebouncedSearchTerm(value);
  }, 300);

  const handleSearch = (value: string) => {
    setSearchTerm(value);
    debouncedSetSearch(value);
  };

  return (
    <Select
      showSearch
      style={{ width: 300 }}
      placeholder="Search..."
      options={options}
      loading={isFetching}
      onSearch={handleSearch}
      filterOption={false}
    />
  );
};

const App = () => (
  <QueryClientProvider client={queryClient}>
    <AsyncSelect />
  </QueryClientProvider>
);

What is expected?

When the user types "John Doe" and the API returns results, the search input should retain the value "test" and display the filtered options below, with the combobox opened.

What is actually happening?

Intermittently, when the options are updated after the API call returns, the search input value is cleared (reset to empty string). This happens inconsistently - sometimes the search value persists correctly, other times it gets wiped out.

The issue appears to be in rc-select's internal state management. When options update and trigger a re-render, onSearch('') is called internally, which clears the search input, hiding the options in consequence.

Environment Info
antd 6.0.0
React 19.2
System MacOS
Browser Chrome 142.0.7444.176

  • Intermittent nature: The bug doesn't happen 100% of the time, making it harder to reproduce consistently. It seems related to timing/race conditions between the options update and internal state management.
    Root cause investigation: The issue appears to stem from rc-select replacing useMergedState with useControlledState for managing searchValue. The older implementation handled controlled/uncontrolled state more robustly:
// Old (worked correctly):
const [mergedSearchValue, setSearchValue] = useMergedState('', {
  value: searchValue !== undefined ? searchValue : inputValue,
  postState: (search) => search || '',
});

// New (causes the bug):
const [internalSearchValue, setSearchValue] = useControlledState('', searchValue);
  • Workaround: The issue can be worked around by making the search input fully controlled via showSearch={{ searchValue, onSearch }} and guarding against internal empty string resets:
const [searchValue, setSearchValue] = useState('');

const handleSearch = (value: string) => {
  // Guard against rc-select internal resets
  if (value === '' && searchValue.length > 1) {
    return;
  }
  setSearchValue(value);
};

<Select
  showSearch={{ searchValue, onSearch: handleSearch }}
  // ...
/>
  • Environment: antd v6.x, React 19.x

Activity

  1. dosubot commented on Nov 27, 2025

    @dosubot

    Hi @aFrameEmilio! I'm Dosu and I’m helping the ant-design team.

    This is a known limitation in Ant Design v6's Select component when using async options and showSearch. The root cause is the switch from useMergedState to useControlledState in the underlying rc-select package, which can cause searchValue to reset unexpectedly during async option updates due to race conditions between internal state and prop changes. This is especially noticeable when options are updated after an API call triggered by onSearch, leading to intermittent clearing of the search input [source].

    The current official guidance is to set showSearch as a boolean and manage search-related props (onSearch, searchValue, autoClearSearchValue) directly on the Select component—not inside showSearch as an object. Using showSearch={{ searchValue, onSearch }} is not officially supported in released versions and may not work as expected [source].

    For advanced scenarios like async option loading, the recommended workaround is to fully control searchValue and onSearch yourself, guarding against unwanted resets (for example, by ignoring empty string resets unless you intend to clear the input). Manual state management is currently the best way to ensure consistent behavior [source].

    There is an ongoing API redesign in rc-select to unify search-related props into a SearchConfig object (so showSearch can be an object), but this is not yet officially released. Backward compatibility is maintained for now, so continue to use the boolean showSearch and set search-related props directly on Select [source].

    If you need more control (e.g., to show searchValue only when focused), you can manage this with onFocus/onBlur handlers and your own state [source].

    To reply, just mention @dosu.


    Share context across your team and agents. Try Dosu.

    Leave Feedback Learn about ant-design with Dosu Add Dosu to your team

  2. added
    🐛 BugAnt Design Team had proved that this is a bug.
    and removed on Nov 28, 2025
  3. zenggpzqbx commented on Nov 28, 2025

    @zenggpzqbx
    Contributor

    这个主要问题是notFoundContent是null的时候不是有效的节点

  4. MadCcc commented on Dec 3, 2025

    @MadCcc
    Member

    Didn't get reproduced, any more details?

  5. zenggpzqbx commented on Dec 4, 2025

    @zenggpzqbx
    Contributor
  6. zenggpzqbx commented on Dec 4, 2025

    @zenggpzqbx
    Contributor
  7. github-actions commented on Dec 20, 2025

    @github-actions
    Contributor

    @zombieJ 这个 issue 已经超过 14 天没有更新或关联 PR。如果您仍在处理这个 issue,请更新进度;如果您无法继续处理,请联系维护者重新分配。

    This issue has been inactive for more than 14 days without any updates or linked PR. If you are still working on this issue, please provide a progress update. If you are unable to continue, please contact the maintainers for reassignment.

  8. andyxmai commented on Jan 2, 2026

    @andyxmai

    This makes dynamic, remote fetching not usable for Select. If a user mis-types, the value gets cleared, and they need to start over.

  9. kimteayon commented on Jan 2, 2026

    @kimteayon
  10. KianChavoshiNejad commented on Jan 2, 2026

    @KianChavoshiNejad

    one way I was able to reproduce this is if we pass in something like

    loading ? Spin component : null
    to the notFoundContent

    and change the loading state in the asynchronous function "onSearch" when typing something and the options returned are an empty array it will wipe the users input

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

Metadata

Metadata

Assignees

Labels

6.x🐛 BugAnt Design Team had proved that this is a bug.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions