Skip to content

AutocompleteInput

Search-as-you-type field for selecting a single item from a search source.

function AutocompleteInputStory(
args: React.ComponentProps<typeof AutocompleteInput>,
) {
const [value, setValue] = useState<SearchableItem | null>(null);
const source = useMemo(() => createStaticSearchSource(people), []);
return (
<AutocompleteInput
{...args}
debounceMs={0}
hasEntriesOnFocus
onChange={setValue}
searchSource={source}
value={value}
/>
);
}
<AutocompleteInputStory {...args} />
function CustomItemsStory(
args: React.ComponentProps<typeof AutocompleteInput>,
) {
const [value, setValue] = useState<SearchableItem<{role: string}> | null>(
null,
);
const source = useMemo(() => createStaticSearchSource(people), []);
return (
<AutocompleteInput
{...args}
debounceMs={0}
hasEntriesOnFocus
onChange={setValue}
renderItem={(item, query) => (
<AutocompleteInputItem
description={item.auxiliaryData?.role}
icon={User}
item={item}
query={query}
/>
)}
searchSource={source}
value={value}
/>
);
}
<CustomItemsStory {...args} />
function DisabledResultsStory(
args: React.ComponentProps<typeof AutocompleteInput>,
) {
const [value, setValue] = useState<SearchableItem<{role: string}> | null>(
null,
);
const source = useMemo(
() => createStaticSearchSource(peopleWithDisabledResult),
[],
);
return (
<AutocompleteInput
{...args}
debounceMs={0}
hasEntriesOnFocus
onChange={setValue}
renderItem={(item, query) => (
<AutocompleteInputItem
description={item.auxiliaryData?.role}
item={item}
query={query}
/>
)}
searchSource={source}
value={value}
/>
);
}
<DisabledResultsStory {...args} />
function AutocompleteInputStory(
args: React.ComponentProps<typeof AutocompleteInput>,
) {
const [value, setValue] = useState<SearchableItem | null>(null);
const source = useMemo(() => createStaticSearchSource(people), []);
return (
<AutocompleteInput
{...args}
debounceMs={0}
hasEntriesOnFocus
onChange={setValue}
searchSource={source}
value={value}
/>
);
}
<AutocompleteInputStory {...args} />
function AutocompleteInputStory(
args: React.ComponentProps<typeof AutocompleteInput>,
) {
const [value, setValue] = useState<SearchableItem | null>(null);
const source = useMemo(() => createStaticSearchSource(people), []);
return (
<AutocompleteInput
{...args}
debounceMs={0}
hasEntriesOnFocus
onChange={setValue}
searchSource={source}
value={value}
/>
);
}
<AutocompleteInputStory {...args} />
function AutocompleteInputStory(
args: React.ComponentProps<typeof AutocompleteInput>,
) {
const [value, setValue] = useState<SearchableItem | null>(null);
const source = useMemo(() => createStaticSearchSource(people), []);
return (
<AutocompleteInput
{...args}
debounceMs={0}
hasEntriesOnFocus
onChange={setValue}
searchSource={source}
value={value}
/>
);
}
<AutocompleteInputStory {...args} />
(args: AutocompleteInputProps) => {
const [value, setValue] = useState<SearchableItem<{role: string}> | null>(
people[1],
);
const source = useMemo(() => createStaticSearchSource(people), []);
return (
<AutocompleteInput
{...args}
debounceMs={0}
hasEntriesOnFocus
onChange={setValue}
searchSource={source}
value={value}
/>
);
}
(args: AutocompleteInputProps) => {
const [value, setValue] = useState<SearchableItem<{role: string}> | null>(
people[0],
);
const source = useMemo(() => createStaticSearchSource(people), []);
return (
<AutocompleteInput
{...args}
debounceMs={0}
onChange={setValue}
searchSource={source}
value={value}
/>
);
}
(args: AutocompleteInputProps) => {
const source = useMemo(() => createStaticSearchSource(people), []);
const [small, setSmall] = useState<SearchableItem | null>(null);
const [medium, setMedium] = useState<SearchableItem | null>(null);
const [large, setLarge] = useState<SearchableItem | null>(null);
return (
<div style={{display: 'grid', gap: 16}}>
<AutocompleteInput
{...args}
debounceMs={0}
label="Small"
onChange={setSmall}
searchSource={source}
size="sm"
value={small}
/>
<AutocompleteInput
{...args}
debounceMs={0}
label="Medium"
onChange={setMedium}
searchSource={source}
value={medium}
/>
<AutocompleteInput
{...args}
debounceMs={0}
label="Large"
onChange={setLarge}
searchSource={source}
size="lg"
value={large}
/>
</div>
);
}
(args: AutocompleteInputProps) => {
const [value, setValue] = useState<SearchableItem | null>(null);
const source = useMemo(() => createAsyncSource(manyPeople), []);
return (
<AutocompleteInput
{...args}
debounceMs={200}
onChange={setValue}
searchSource={source}
value={value}
/>
);
}
(args: AutocompleteInputProps) => {
const [value, setValue] = useState<SearchableItem | null>(null);
const source = useMemo<SearchSource<SearchableItem>>(
() => ({
bootstrap: () => [],
search: async () => Promise.reject(new Error('Network error')),
}),
[],
);
return (
<AutocompleteInput
{...args}
debounceMs={0}
onChange={setValue}
searchSource={source}
value={value}
/>
);
}
function AutocompleteInputStory(
args: React.ComponentProps<typeof AutocompleteInput>,
) {
const [value, setValue] = useState<SearchableItem | null>(null);
const source = useMemo(() => createStaticSearchSource(people), []);
return (
<AutocompleteInput
{...args}
debounceMs={0}
hasEntriesOnFocus
onChange={setValue}
searchSource={source}
value={value}
/>
);
}
<AutocompleteInputStory {...args} />
Search by name or role.
function AutocompleteInputStory(
args: React.ComponentProps<typeof AutocompleteInput>,
) {
const [value, setValue] = useState<SearchableItem | null>(null);
const source = useMemo(() => createStaticSearchSource(people), []);
return (
<AutocompleteInput
{...args}
debounceMs={0}
hasEntriesOnFocus
onChange={setValue}
searchSource={source}
value={value}
/>
);
}
<AutocompleteInputStory {...args} />
() => {
const [value, setValue] = useState<SearchableItem | null>(null);
const [query, setQuery] = useState('');
const source = useMemo(() => createStaticSearchSource(people), []);
return (
<BaseAutocompleteInput
debounceMs={0}
hasEntriesOnFocus
onChange={setValue}
onQueryChange={setQuery}
placeholder="Search people"
query={query}
searchSource={source}
value={value}
/>
);
}
(args: AutocompleteInputProps) => {
const [value, setValue] = useState<SearchableItem | null>(null);
const source = useMemo(() => createStaticSearchSource(manyPeople), []);
return (
<AutocompleteInput
{...args}
debounceMs={0}
hasEntriesOnFocus
maxMenuItems={12}
onChange={setValue}
searchSource={source}
value={value}
/>
);
}
({
isOptional: _io,
isRequired: _ir,
...args
}: AutocompleteInputProps) => {
const source = useMemo(() => createStaticSearchSource(people), []);
const [required, setRequired] = useState<SearchableItem | null>(null);
const [optional, setOptional] = useState<SearchableItem | null>(null);
return (
<div style={{display: 'grid', gap: 16}}>
<AutocompleteInput
{...args}
debounceMs={0}
isRequired
label="Required assignee"
onChange={setRequired}
searchSource={source}
value={required}
/>
<AutocompleteInput
{...args}
debounceMs={0}
isOptional
label="Optional reviewer"
onChange={setOptional}
searchSource={source}
value={optional}
/>
</div>
);
}
<AutocompleteInput
{...args}
onChange={() => {}}
searchSource={createStaticSearchSource(people)}
value={people[0]}
/>

Search-as-you-type field for selecting a single item from a search source.

When isOptional: false, isRequired: false

PropTypeDefaultDescription
classNamestringAdditional CSS class names applied to the input wrapper.
data-testidstringTest ID applied to the input wrapper.
debounceMsnumber150Debounce delay in milliseconds before search runs.
descriptionReactNodeSupporting text rendered below the label.
emptySearchResultsTextstring'No results found'Empty state text.
errorTextstring'Something went wrong'Text shown in the menu when a search fails.
hasAutoFocusbooleanfalseWhether to focus the input on mount.
hasClearbooleantrueWhether to show a clear button when a value is selected.
hasEntriesOnFocusbooleanfalseWhether to show bootstrap results on focus before typing.
isDisabledbooleanfalseWhether the input is disabled.
isReadOnlybooleanfalseWhether the value is displayed without allowing focus or interaction.
isLabelHiddenbooleanfalseWhether to visually hide the label.
label*stringField label.
labelIconIconComponentIcon shown before the label.
labelTooltipReactNodeTooltip content shown next to the label.
maxMenuItemsnumber10Maximum number of menu items.
onChange*(item: T | null) => voidCalled when selection changes.
onOpenChange(isOpen: boolean) => voidCalled when the result popover opens or closes.
onQueryChange(query: string) => voidCalled when the query changes.
placeholderstringPlaceholder text.
refRef<HTMLDivElement>Ref forwarded to the field root.
renderItem(item: T, query: string) => ReactNodeCustom result renderer. Receives the item and active query.
searchSource*SearchSource<T>Provides results for the menu. Use createStaticSearchSource for in-memory data, or implement SearchSource for async/remote search.
size"sm" | "md" | "lg"'md'Visual size.
startIconIconComponentIcon shown before the input.
statusInputStatusValidation status displayed below the selector.
styleCSSPropertiesInline styles applied to the input wrapper.
value*T | nullSelected item.
isOptionalfalse
isRequiredfalse

When isOptional: true, isRequired: false

PropTypeDefaultDescription
classNamestringAdditional CSS class names applied to the input wrapper.
data-testidstringTest ID applied to the input wrapper.
debounceMsnumber150Debounce delay in milliseconds before search runs.
descriptionReactNodeSupporting text rendered below the label.
emptySearchResultsTextstring'No results found'Empty state text.
errorTextstring'Something went wrong'Text shown in the menu when a search fails.
hasAutoFocusbooleanfalseWhether to focus the input on mount.
hasClearbooleantrueWhether to show a clear button when a value is selected.
hasEntriesOnFocusbooleanfalseWhether to show bootstrap results on focus before typing.
isDisabledbooleanfalseWhether the input is disabled.
isReadOnlybooleanfalseWhether the value is displayed without allowing focus or interaction.
isLabelHiddenbooleanfalseWhether to visually hide the label.
label*stringField label.
labelIconIconComponentIcon shown before the label.
labelTooltipReactNodeTooltip content shown next to the label.
maxMenuItemsnumber10Maximum number of menu items.
onChange*(item: T | null) => voidCalled when selection changes.
onOpenChange(isOpen: boolean) => voidCalled when the result popover opens or closes.
onQueryChange(query: string) => voidCalled when the query changes.
placeholderstringPlaceholder text.
refRef<HTMLDivElement>Ref forwarded to the field root.
renderItem(item: T, query: string) => ReactNodeCustom result renderer. Receives the item and active query.
searchSource*SearchSource<T>Provides results for the menu. Use createStaticSearchSource for in-memory data, or implement SearchSource for async/remote search.
size"sm" | "md" | "lg"'md'Visual size.
startIconIconComponentIcon shown before the input.
statusInputStatusValidation status displayed below the selector.
styleCSSPropertiesInline styles applied to the input wrapper.
value*T | nullSelected item.
isOptional*true
isRequiredfalse

When isOptional: false, isRequired: true

PropTypeDefaultDescription
classNamestringAdditional CSS class names applied to the input wrapper.
data-testidstringTest ID applied to the input wrapper.
debounceMsnumber150Debounce delay in milliseconds before search runs.
descriptionReactNodeSupporting text rendered below the label.
emptySearchResultsTextstring'No results found'Empty state text.
errorTextstring'Something went wrong'Text shown in the menu when a search fails.
hasAutoFocusbooleanfalseWhether to focus the input on mount.
hasClearbooleantrueWhether to show a clear button when a value is selected.
hasEntriesOnFocusbooleanfalseWhether to show bootstrap results on focus before typing.
isDisabledbooleanfalseWhether the input is disabled.
isReadOnlybooleanfalseWhether the value is displayed without allowing focus or interaction.
isLabelHiddenbooleanfalseWhether to visually hide the label.
label*stringField label.
labelIconIconComponentIcon shown before the label.
labelTooltipReactNodeTooltip content shown next to the label.
maxMenuItemsnumber10Maximum number of menu items.
onChange*(item: T | null) => voidCalled when selection changes.
onOpenChange(isOpen: boolean) => voidCalled when the result popover opens or closes.
onQueryChange(query: string) => voidCalled when the query changes.
placeholderstringPlaceholder text.
refRef<HTMLDivElement>Ref forwarded to the field root.
renderItem(item: T, query: string) => ReactNodeCustom result renderer. Receives the item and active query.
searchSource*SearchSource<T>Provides results for the menu. Use createStaticSearchSource for in-memory data, or implement SearchSource for async/remote search.
size"sm" | "md" | "lg"'md'Visual size.
startIconIconComponentIcon shown before the input.
statusInputStatusValidation status displayed below the selector.
styleCSSPropertiesInline styles applied to the input wrapper.
value*T | nullSelected item.
isOptionalfalse
isRequired*true

Internal combobox engine used by AutocompleteInput and TagsInput.

PropTypeDefaultDescription
anchorRefRefObject<HTMLElement | null>Ref to the element the result popover should align to.
ariaDescribedBystringIDs describing the input.
ariaLabelstringAccessible name for the input. Use when no visible <label> is tied to it, such as inside an InputGroup where the group owns the label.
classNamestringAdditional CSS class names applied to the input.
data-testidstringTest ID applied to the input element.
debounceMsnumber150Debounce delay in milliseconds before search runs.
emptySearchResultsTextstring'No results found'Empty state text.
errorTextstring'Something went wrong'Text shown in the menu when a search fails.
hasAutoFocusbooleanfalseWhether to focus the input on mount.
hasEntriesOnFocusbooleanfalseWhether to show bootstrap results on focus before typing.
hasReopenOnSelectbooleanfalseWhether to re-bootstrap results after selecting an item. Useful for multi-select comboboxes where the user picks several items in a row.
inputIdstringOptional ID for the input.
isDisabledbooleanfalseWhether the input is disabled.
isReadOnlybooleanfalseWhether the value is displayed without allowing focus or interaction.
isRequiredbooleanfalseWhether the input is required.
maxMenuItemsnumber10Maximum number of menu items.
onChange*(item: T | null) => voidCalled when a result is selected.
onKeyDown(event: KeyboardEvent<HTMLInputElement>) => voidKeyboard handler invoked before internal navigation.
onOpenChange(isOpen: boolean) => voidCalled when the result popover opens or closes.
onQueryChange*(query: string) => voidCalled when the query changes.
placeholderstring'Search...'Placeholder text.
query*stringCurrent query string.
refRef<HTMLInputElement>Ref forwarded to the input.
renderItem(item: T) => ReactNodeCustom result renderer.
searchSource*SearchSource<T>Provides results for the menu. Use createStaticSearchSource for in-memory data, or implement SearchSource for async/remote search.
size"sm" | "md" | "lg"'md'Visual size.
styleCSSPropertiesInline styles applied to the input.
value*T | nullSelected item.

Default layout for AutocompleteInput and TagsInput result rows. When the item has a pre-rendered `element`, it is returned directly. Otherwise the component renders a flex row with an optional icon, primary label, and description.

When Variant 1

PropTypeDefaultDescription
item*SearchableItem & {element: ReactNode}Search result item with custom element content.
querystring | string[]Literal query or queries highlighted in the item label.

When Variant 2

PropTypeDefaultDescription
classNamestringAdditional CSS class names applied to the item layout.
data-testidstringTest ID applied to the item layout.
descriptionReactNodeSupporting text displayed below the label.
iconIconComponentIcon or avatar rendered before the label.
item*SearchableItem & {element?: undefined}Search result item without a custom element.
refRef<HTMLDivElement>Ref forwarded to the item layout.
styleCSSPropertiesInline styles applied to the item layout.
querystring | string[]Literal query or queries highlighted in the item label.