Skip to content

fix: allow loadOptions('') to be called when input is cleared #6045

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/gentle-eyes-sell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'react-select': patch
'storybook': patch
---

Introduces a new optional prop allowEmptySearch to the Async Select component.
10 changes: 9 additions & 1 deletion packages/react-select/src/useAsync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ export interface AsyncAdditionalProps<Option, Group extends GroupBase<Option>> {
* Async select is not currently waiting for loadOptions to resolve
*/
isLoading?: boolean;
/**
* When set to `true`, the `loadOptions` function will be called even when the input is empty (`''`).
* This allows consumers to handle empty input searches (e.g., return a default set of results).
* If `false` (default), the input will reset without triggering `loadOptions('')`.
*/
allowEmptySearch?: boolean;
}

export type AsyncProps<
Expand All @@ -55,6 +61,7 @@ export default function useAsync<
isLoading: propsIsLoading = false,
onInputChange: propsOnInputChange,
filterOption = null,
allowEmptySearch,
...restSelectProps
}: AsyncProps<Option, IsMulti, Group> & AdditionalProps): StateManagerProps<
Option,
Expand Down Expand Up @@ -143,7 +150,7 @@ export default function useAsync<
actionMeta,
propsOnInputChange
);
if (!inputValue) {
if (!inputValue && !allowEmptySearch) {
lastRequest.current = undefined;
setStateInputValue('');
setLoadedInputValue('');
Expand Down Expand Up @@ -183,6 +190,7 @@ export default function useAsync<
loadedInputValue,
optionsCache,
propsOnInputChange,
allowEmptySearch,
]
);

Expand Down
44 changes: 44 additions & 0 deletions storybook/stories/AsyncPromisesWithAllowEmptySearch.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { ComponentMeta } from '@storybook/react';
import * as React from 'react';
import AsyncSelect from 'react-select/async';

import { Field } from '../components';
import { ColourOption, colourOptions } from '../data';

export default {
title: 'Select/AsyncPromises',
component: AsyncSelect,
argTypes: {},
} as ComponentMeta<typeof AsyncSelect>;

export function AsyncPromises() {
return (
<Field label="Async Promises" htmlFor="async-promises">
<AsyncSelect
inputId="async-promises"
cacheOptions
defaultOptions
loadOptions={promiseOptions}
allowEmptySearch
/>
</Field>
);
}

// =============================================================================
// Utils
// =============================================================================

function filterColors(inputValue: string) {
return colourOptions.filter((i) =>
i.label.toLowerCase().includes(inputValue.toLowerCase())
);
}

function promiseOptions(inputValue: string) {
return new Promise<ColourOption[]>((resolve) => {
setTimeout(() => {
resolve(filterColors(inputValue));
}, 1000);
});
}