# react-select-async-paginate

> Wrapper above react-select that supports pagination on menu scroll

Latest version **0.7.11** (published 2025-07-04) · MIT license · 0 weekly downloads

## Install

```sh
npm install react-select-async-paginate
pnpm add react-select-async-paginate
yarn add react-select-async-paginate
bun add react-select-async-paginate
```

## Health

**Score 45/100 (D)** — status: stable.

Positive: has types; esm support; no vulnerabilities.

Warnings: low downloads; pre 1.0.

Negative: stale.

## Facts

| | |
|---|---|
| Version | 0.7.11 |
| Published | 2025-07-04 |
| First published | 2018-03-15 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 6 |
| Unpacked size | 118 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 331 |
| Author | Vadim Taits |
| Maintainers | vtaits |
| Keywords | react, react-select, async, pagination |

## Links

- npm: https://www.npmjs.com/package/react-select-async-paginate
- Repository: https://github.com/vtaits/react-select-async-paginate
- Homepage: https://github.com/vtaits/react-select-async-paginate/tree/master/packages/react-select-async-paginate
- Issues: https://github.com/vtaits/react-select-async-paginate/issues
- npm.io page: https://npm.io/package/react-select-async-paginate

## Dependencies (6)

- [krustykrab](https://npm.io/package/krustykrab.md) ^1.1.0
- [use-latest](https://npm.io/package/use-latest.md) ^1.3.0
- [sleep-promise](https://npm.io/package/sleep-promise.md) ^9.1.0
- [use-is-mounted-ref](https://npm.io/package/use-is-mounted-ref.md) ^1.5.0
- [@vtaits/use-lazy-ref](https://npm.io/package/@vtaits/use-lazy-ref.md) ^0.1.4
- [@seznam/compose-react-refs](https://npm.io/package/@seznam/compose-react-refs.md) ^1.0.6

## Alternatives

- [mobx-react](https://npm.io/package/mobx-react.md) — 2.8M weekly downloads
- [rc-tree](https://npm.io/package/rc-tree.md) — 2.6M weekly downloads
- [@react-oauth/google](https://npm.io/package/@react-oauth/google.md) — 1.3M weekly downloads
- [@wagmi/connectors](https://npm.io/package/@wagmi/connectors.md) — 877.0K weekly downloads
- [vee-validate](https://npm.io/package/vee-validate.md) — 836.4K weekly downloads

## Recent versions

- 0.7.11 (latest) — 2025-07-04
- 1.0.0-alpha.3 (alpha) — 2025-10-01
- 1.0.0-alpha.2 — 2025-08-11
- 1.0.0-alpha.1 — 2025-06-09
- 0.7.10 — 2025-04-19
- 1.0.0-alpha.0 — 2025-01-28
- 0.7.9 — 2024-12-26
- 0.7.8 — 2024-12-26
- 0.7.7 — 2024-12-06
- 0.7.6 — 2024-09-18
- 0.7.5 — 2024-07-26
- 0.7.4 — 2024-04-11
- 0.7.3 — 2023-06-23
- 0.7.2 — 2022-12-14
- 0.7.1 — 2022-12-12
- … 40 more at https://npm.io/package/react-select-async-paginate/versions

## README

[![NPM](https://img.shields.io/npm/v/react-select-async-paginate.svg)](https://www.npmjs.com/package/react-select-async-paginate)
[![codecov.io](https://codecov.io/gh/vtaits/react-select-async-paginate/branch/master/graph/badge.svg)](https://codecov.io/gh/vtaits/react-select-async-paginate)
![dependencies status](https://img.shields.io/librariesio/release/npm/react-select-async-paginate)

# react-select-async-paginate

Wrapper above `react-select` that supports pagination on menu scroll.

## Sandbox examples

- [Simple](https://codesandbox.io/s/o75rno2w65)
- [Multi](https://codesandbox.io/s/2323yrlo9r)
- [Creatable](https://codesandbox.io/s/5ycdz)
- [Creatable with adding new options](https://codesandbox.io/s/6pznz)
- [Initial options](https://codesandbox.io/s/q111nqw9j)
- [Autoload](https://codesandbox.io/s/v8pkw)
- [Debounce](https://codesandbox.io/s/5y2xq39v5k)
- [Request by page number](https://codesandbox.io/s/10r1k12vk7)
- [Customization check of the need of load options](https://codesandbox.io/s/kokz6j65zv)
- [Grouped options](https://codesandbox.io/s/oxv62x8j4y)
- [Custom select base](https://codesandbox.io/s/l2pjrv0ryl)
- [Manual control of input value and menu opening](https://codesandbox.io/s/6y34j51k1n)
- [Show selected items on top of the menu](https://codesandbox.io/p/sandbox/gpdkwk)
- [react-hook-form integration](https://codesandbox.io/s/x7vw8c)

## Versions

| react-select | react-select-async-paginate |
|--------------|-----------------------------|
| 5.x | 0.6.x, 0.7.x |
| 4.x | 0.5.x |
| 3.x | 0.5.x, 0.4.x, ^0.3.2 |
| 2.x | 0.3.x, 0.2.x |
| 1.x | 0.1.x |

## Installation

```
npm install react-select react-select-async-paginate
```

or

```
yarn add react-select react-select-async-paginate
```

or

```
bun add react-select react-select-async-paginate
```

## Usage

`AsyncPaginate` is an alternative of `Async` but supports loading page by page. It is wrapper above default `react-select` thus it accepts all props of default `Select`. And there are some new props:

### loadOptions

Required. Async function that take next arguments:

1. Current value of search input.
2. Loaded options for current search.
3. Collected additional data e.g. current page number etc. For first load it is `additional` from props, for next is `additional` from previous response for current search. `null` by default.

It should return next object:

```
{
  options: Array,
  hasMore: boolean,
  additional?: any,
}
```

It similar to `loadOptions` from `Select.Async` but there is some differences:

1. Loaded options as 2nd argument.
2. Additional data as 3nd argument.
3. Not supports callback.
4. Should return `hasMore` for detect end of options list for current search.

### debounceTimeout

Not required. Number. Debounce timeout for `loadOptions` calls. `0` by default.

### additional

Not required. Default `additional` for first request for every search.

### defaultAdditional

Not required. Default `additional` for empty search if `options` or `defaultOptions` defined.

### shouldLoadMore

Not required. Function. By default new options will load only after scroll menu to bottom. Arguments:

- scrollHeight
- clientHeight
- scrollTop

Should return boolean.

### reduceOptions

Not required. Function. By default new loaded options are concat with previous. Arguments:

- previous options
- loaded options
- next additional

Should return new options.

### reloadOnErrorTimeout

Not required. Number. Time in milliseconds to retry a request after an error

### clearCacheOnSearchChange

Not required. Boolean. Clear all cached options on search change

### clearCacheOnMenuClose

Not required. Boolean. Clear all cached options on menu close

### cacheUniqs

Not required. Array. Works as 2nd argument of `useEffect` hook. When one of items changed, `AsyncPaginate` cleans all cached options.

### loadOptionsOnMenuOpen

Not required. Boolean. If `false` options will not load on menu opening.

### mapOptionsForMenu

Not required. Function. Post-mapping of loaded options to display them in the menu. Can be used to put selected options to top of the list.

### selectRef

Ref for take `react-select` instance.

## Example

### offset way

```javascript
import { AsyncPaginate } from 'react-select-async-paginate';

...

/*
 * assuming the API returns something like this:
 *   const json = {
 *     results: [
 *       {
 *         value: 1,
 *         label: 'Audi',
 *       },
 *       {
 *         value: 2,
 *         label: 'Mercedes',
 *       },
 *       {
 *         value: 3,
 *         label: 'BMW',
 *       },
 *     ],
 *     has_more: true,
 *   };
 */

async function loadOptions(search, loadedOptions) {
  const response = await fetch(`/awesome-api-url/?search=${search}&offset=${loadedOptions.length}`);
  const responseJSON = await response.json();

  return {
    options: responseJSON.results,
    hasMore: responseJSON.has_more,
  };
}

<AsyncPaginate
  value={value}
  loadOptions={loadOptions}
  onChange={setValue}
/>
```

### page way

```javascript
import { AsyncPaginate } from 'react-select-async-paginate';

...

async function loadOptions(search, loadedOptions, { page }) {
  const response = await fetch(`/awesome-api-url/?search=${search}&page=${page}`);
  const responseJSON = await response.json();

  return {
    options: responseJSON.results,
    hasMore: responseJSON.has_more,
    additional: {
      page: page + 1,
    },
  };
}

<AsyncPaginate
  value={value}
  loadOptions={loadOptions}
  onChange={setValue}
  additional={{
    page: 1,
  }}
/>
```

## Grouped options

You can use `reduceGroupedOptions` util to group options by `label` key.

```javascript
import { AsyncPaginate, reduceGroupedOptions } from 'react-select-async-paginate';

/*
 * assuming the API returns something like this:
 *   const json = {
 *     options: [
 *       label: 'Cars',
 *       options: [
 *         {
 *           value: 1,
 *           label: 'Audi',
 *         },
 *         {
 *           value: 2,
 *           label: 'Mercedes',
 *         },
 *         {
 *           value: 3,
 *           label: 'BMW',
 *         },
 *       ]
 *     ],
 *     hasMore: true,
 *   };
 */

...

<AsyncPaginate
  {...otherProps}
  reduceOptions={reduceGroupedOptions}
/>
```

## Replacing react-select component

You can use `withAsyncPaginate` HOC.

```javascript
import { withAsyncPaginate } from 'react-select-async-paginate';

...

const CustomAsyncPaginate = withAsyncPaginate(CustomSelect);
```

### typescript

Describing type of component with extra props (example with `Creatable`):

```typescript
import type { ReactElement } from 'react';
import type { GroupBase } from 'react-select';
import Creatable from 'react-select/creatable';
import type { CreatableProps } from 'react-select/creatable';

import { withAsyncPaginate } from 'react-select-async-paginate';
import type {
  UseAsyncPaginateParams,
  ComponentProps,
} from 'react-select-async-paginate';

type AsyncPaginateCreatableProps<
OptionType,
Group extends GroupBase<OptionType>,
Additional,
IsMulti extends boolean,
> =
  & CreatableProps<OptionType, IsMulti, Group>
  & UseAsyncPaginateParams<OptionType, Group, Additional>
  & ComponentProps<OptionType, Group, IsMulti>;

type AsyncPaginateCreatableType = <
OptionType,
Group extends GroupBase<OptionType>,
Additional,
IsMulti extends boolean = false,
>(props: AsyncPaginateCreatableProps<OptionType, Group, Additional, IsMulti>) => ReactElement;

const AsyncPaginateCreatable = withAsyncPaginate(Creatable) as AsyncPaginateCreatableType;
```

## Replacing Components

Usage of replacing components is similar with `react-select`, but there is one difference. If you redefine `MenuList` you should wrap it with `wrapMenuList` for workaround of some internal bugs of `react-select`.

```javascript
import { AsyncPaginate, wrapMenuList } from 'react-select-async-paginate';

...

const MenuList = wrapMenuList(CustomMenuList);

<AsyncPaginate
  {...otherProps}
  components={{
    ...otherComponents,
    MenuList,
  }}
/>
```

## Extended usage

If you want construct own component that uses logic of `react-select-async-paginate` inside, you can use next hooks:

- `useAsyncPaginate`
- `useAsyncPaginateBase`
- `useComponents`

```javascript
import {
  useAsyncPaginate,
  useComponents,
} from 'react-select-async-paginate';

...

const CustomAsyncPaginateComponent = ({
  options,
  defaultOptions,
  additional,
  loadOptionsOnMenuOpen,
  debounceTimeout,
  filterOption,
  reduceOptions,
  shouldLoadMore,

  components: defaultComponents,

  value,
  onChange,
}) => {
  const asyncPaginateProps = useAsyncPaginate({
    options,
    defaultOptions,
    additional,
    loadOptionsOnMenuOpen,
    debounceTimeout,
    filterOption,
    reduceOptions,
    shouldLoadMore,
  });

  const components = useComponents(defaultComponents);

  return (
    <CustomSelect
      {...asyncPaginateProps}
      components={components}
      value={value}
      onChange={onChange}
    />
  );
}
```

`useComponents` provides redefined `MenuList` component by default. If you want redefine it, you should also wrap in with `wrapMenuList`.

---
_Source: https://npm.io/package/react-select-async-paginate · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
