# @rc-component/select gives you the behaviour of a select and none of the styling

> @rc-component/select is the headless Select component from the Ant Design ecosystem, published as a composable React component with search, async friendly option data, custom rendering and virtual scrolling. It suits teams that need a select that behaves correctly and looks like their own design system, and it is the wrong choice if you want a styled component on day one.

**react-component/select** — 🎯 Composable Select component for React, with search, async-friendly option data, custom rendering, and virtual scrolling.

- Repository: https://github.com/react-component/select
- Website: https://react-component.github.io/select
- Stars: 940 · Forks: 481
- Language: TypeScript
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/react-component-select

## A headless select inside the Ant Design ecosystem

@rc-component/select is the underlying Select used by the Ant Design ecosystem, published on its own as a scoped package. The README describes it as a composable Select component for React, with search, async friendly option data, custom rendering and virtual scrolling, and the repository carries the Ant Design ecosystem badge.

The word composable is the one to hold on to. This is a behaviour package, not a styled component. It ships the parts of a select that are genuinely hard to get right: the keyboard and focus handling, the popup positioning, the option filtering, the multi select tag management, the virtual list. It does not ship a design. The consumer supplies the class names and the CSS, which is why the props include classNames for semantic class names and styles for semantic styles, both typed as a partial record keyed by a SemanticName union.

The audiences are therefore two. The first is a team maintaining a component library that needs a select with Ant Design's behaviour but its own visual language. The second is a team building an Ant Design application that has hit the point where the themed component cannot do what it needs, for example a custom option renderer with async data.

The package is TypeScript first. The manifest points main at ./lib/index, module at ./es/index and types at ./es/index.d.ts, so consumers get ES modules, a CommonJS build and declaration files, and the published files list includes the es and lib directories plus the assets stylesheets.

## Options as data, with the old children API kept around

The data story is the clearest signal of where the library is heading. The highlight table lists three supported shapes: options data, legacy Option children, and grouped options. The API table marks children as legacy option children with the note to prefer options for new code, and the Option component is described as a legacy placeholder component, with OptGroup described in the same terms.

So the current contract is that you pass an array of option objects:

```tsx
import Select from '@rc-component/select';
import '@rc-component/select/assets/index.css';

export default () => (
  <Select
    placeholder="Select a user"
    options={[
      { value: 'jack', label: 'Jack' },
      { value: 'lucy', label: 'Lucy' },
      { value: 'yiminghe', label: 'Yiminghe' },
    ]}
  />
);
```

The options prop is typed as OptionType[], and the field names are not fixed. The fieldNames prop customises option field names, so a backend payload can be mapped onto the internal shape without a transformation step, and the optionLabelProp prop names the option prop used as the selected label, which is how you display something other than the label field while still storing the raw value.

Because options are plain data, the async case is a first class concern rather than an afterthought. You can hold the option list in state, fill it in when your request resolves, and pass the new array back in. The list of modes is equally broad: single select, multiple, tags and combobox, with mode typed as combobox, multiple or tags, and the legacy value shape selected with the labelInValue prop when you want labeled value objects instead of raw values.

## Search moved into a showSearch config object

The most important thing to notice in the API table is the cluster of deprecations. autoClearSearchValue, filterOption, filterSort, onSearch, optionFilterProp and searchValue all appear as top level props marked deprecated, each with a pointer to the same name under showSearch. The showSearch prop itself is typed as boolean or a SearchConfig object.

That is a coherent migration rather than scattered cruft, because a boolean showSearch flag cannot carry the configuration those six props used to hold. The SearchConfig type has autoClearSearchValue to clear the search input after selecting or deselecting in multiple mode, filterOption to filter options by search input, filterSort to sort the filtered options with a signature that receives the current searchValue, onSearch called when the search input changes, optionFilterProp naming the option prop used for filtering, and searchValue for a controlled search input.

Two behaviours here are easy to get wrong when writing search yourself. filterSort receives a comparator plus an info object carrying searchValue, so you can sort filtered results by relevance to the query rather than alphabetically. And the controlled search input is a first class option, which is what makes the async friendly story work: you control the query, you fetch, and the results come back into the options array.

One prop is redefined rather than deprecated. The API notes say Select also accepts public props from BaseSelect, except showSearch, which is redefined by Select. So if you are porting from a base select component, that is the one name to watch.

## Virtual scrolling with a fixed item height assumption

The Scale row of the highlights table says virtual scrolling with configurable item height, and the props behind it are numeric and blunt. listHeight sets the popup list height and defaults to 200. listItemHeight sets the popup list item height and defaults to 20. The virtual prop disables virtual scrolling when set to false, and it is true by default.

The mechanism is in the dependency list: @rc-component/virtual-list at ^1.2.0, alongside @rc-component/trigger for the popup, @rc-component/overflow for the tag overflow behaviour in multiple mode, @rc-component/util for the shared helpers and clsx for class name composition. That is a deliberately small runtime surface, all of it from the same rc-component family, and it explains why the package can be used as a building block rather than only as a styled component.

The constraint implied by the API is worth naming. Virtual scrolling needs a constant row height to compute the scroll window, and listItemHeight defaults to 20 pixels. If your options render at a different height, either set listItemHeight to match or turn virtual off with virtual={false}, accepting that the list then renders every option. There is no per option height measurement in the documented API.

There is also maxCount, the maximum selected item count, which is how you cap a multi select, and onDeselect, onSelect, onActive and onChange give you the event surface. onChange hands back the selected value and optionally the option, or an array of options in multiple mode.

## Rendering hooks for options, labels and icons

The Rendering row of the highlights table lists custom option, label, selected item, clear and menu icons, and the props back that up.

optionRender is typed as a function taking the original option and an info object with the index, so you can decorate an option in place without rebuilding your data. labelRender takes props of a LabelInValueType and returns a ReactNode, which is what you use to customise how the chosen value appears in the closed input. menuItemSelectedIcon is a RenderNode for the check mark next to the selected option, and classNames and styles give you the semantic hooks for every part of the component.

Two small props do more work than they look. autoComplete sets the browser autocomplete hint for the search input and defaults to new-password, which is a deliberate choice to stop the browser from autofilling a saved credential into your search field. backfill backfills the active option into the input and only works in combobox mode.

The methods table is short: blur removes focus and focus focuses the selector, both with no parameters. labelInValue is the switch for working with labeled value objects rather than raw values, and it pairs with the labelRender hook. If you are wiring a select into a form library, that combination is usually the shape you want, because it preserves the display label across remounts when the option object itself is not in your state.

## Installing it and running the documentation site

Installation is a single command, and the README gives it directly:

```bash
npm install @rc-component/select
```

The stylesheet is a separate import, and it is worth noticing that the usage example imports it explicitly:

```tsx
import '@rc-component/select/assets/index.css';
```

The published files list includes assets/*.css and assets/*.less alongside the es and lib directories, and the compile script runs father build and then lessc on assets/index.less to produce assets/index.css. So the package ships the compiled stylesheet, but it does not inject it, and the class names it uses are yours to override through the classNames and styles props.

To explore the component locally, the README points at the dumi site:

```bash
npm install
npm start
```

and then tells you to open http://localhost:8000. The scripts confirm the tooling: start runs dumi dev, build runs dumi build, prepare runs husky and dumi setup, compile runs father build with the lessc step, prepublishOnly runs the compile and rc-np publish flow, test runs rc-test, lint runs eslint over src, docs and tests, and tsc runs tsc --noEmit.

The repository layout is conventional for this family: src for the component, tests for the jest suites, docs for the dumi examples, typings for ambient type declarations, plus a .dumirc.ts, a jest.config.js, an eslint config and a vercel.json for the documentation site deployment.

## What you give up, and what the deprecations cost you

The first cost of a headless component is the obvious one: nothing looks finished until you write the styles. A team that wanted a working select this afternoon and is willing to accept Ant Design's look is better served by the styled component in the Ant Design ecosystem, and this package is the wrong choice for them. The second cost is that the headless component exposes its internals, and the API table shows the churn. Six top level search props are already deprecated in version 1.12.0, and the children based Option and OptGroup are described as legacy placeholder components.

That is a maintenance signal rather than a defect, but it is a signal. A component that is still reshaping its own prop surface is a component whose API will move again, and code written against the top level filterOption prop will need migrating to showSearch.filterOption. The upside of the same churn is that the migration path is documented prop by prop, so the work is mechanical.

Two details in the manifest are worth a second look. The engines field says node >=8.x, which is almost certainly inherited rather than tested, since the dev dependencies are on the far side of that, and the peer dependencies list react and react-dom as * with no version range at all, so npm will not warn you when you install it against a React version the component has never seen.

On maintenance, the repository is not archived, the last push was on 2026-10-13, and the releases are frequent: @rc-component/select 1.12.0 on 2026-10-13, 1.11.0 on 2026-08-14 and 1.10.1 on 2026-08-11. The licence is MIT, so there is no copyleft obligation on an application that embeds it.

## Conclusion

Adopt @rc-component/select when you are building a select that has to match your own design system and you want the Ant Design behaviour without the Ant Design skin, and use the styled Ant Design component instead when a consistent look matters more than control. Before you commit, check which of the top level search props you are using against the showSearch configuration, since several of them are already marked deprecated in version 1.12.0, and import the stylesheet yourself since the package ships no default look. The last push was on 2026-10-13 and the releases are published under the @rc-component/select scope.

## FAQ

### What is @rc-component/select?

It is the Select component from the Ant Design ecosystem, published as a composable React component with search, async friendly option data, custom rendering and virtual scrolling. The package is TypeScript first and published under the @rc-component scope.

### How do I install @rc-component/select and use it?

Run npm install @rc-component/select, then pass your option data through the options prop and import the stylesheet with import '@rc-component/select/assets/index.css'. The README warns to prefer options for new code over the legacy Option children.

### Which props in @rc-component/select are deprecated?

The top level autoClearSearchValue, filterOption, filterSort, onSearch, optionFilterProp and searchValue props are deprecated in favour of the same names under the showSearch configuration object, which is typed as boolean or a SearchConfig.

### How does virtual scrolling work in @rc-component/select?

Virtual scrolling is on by default and can be disabled with the virtual prop set to false. The popup size is controlled by listHeight, which defaults to 200, and the row size by listItemHeight, which defaults to 20, with the list implementation provided by the @rc-component/virtual-list dependency.

### What licence is @rc-component/select released under?

MIT. The manifest declares the licence as MIT and the repository contains both LICENSE and LICENSE.md files, so there is no copyleft requirement on applications that embed it.

## Sources

- [License: MIT](https://github.com/react-component/select/blob/master/LICENSE)
- [Project website](https://react-component.github.io/select)
- [react-component/select on GitHub](https://github.com/react-component/select)
- [README](https://github.com/react-component/select/blob/master/README.md)
- [Releases](https://github.com/react-component/select/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/react-component-select
