import { SearchInput } from '@uhg-abyss/web/ui/SearchInput';() => { const MockData = utils.useSearchInputMock();
const handleSearch = (data) => { console.log('Searched', data); };
return ( <SearchInput placeholder="Placeholder text" label="Search Sandbox" onSearch={handleSearch} options={MockData} /> );};Usage
SearchInput is designed specifically for site-wide search functionality, and is no longer considered a typical form input component. The recommended usage context is for a search input field that is used to search for items within a site and display results.
For usages that require users to fill out a form with search functionality, it is recommended you use SelectInput with the isSearchable prop.
Note:
SearchInputdoes not support the following V1 SearchInput props:validators,errorMessage,isDisabled,isRequired,modelandsubText.SearchInputis no longer compatible withFormProvideranduseForm.
Variants
Default search
The default variant for SearchInput is a basic search input field that, on search, provides the search term to the onSearch callback.
Note: Most code examples below use the type-ahead variant because of its increased functionality. Any props that are NOT compatible with the default variant are designated below by the following badge:
Type-ahead search
Utilize the isTypeAhead prop to enable type-ahead search functionality along with a drop-down menu of options that are filtered based on the search term. Same as with the default variant, the onSearch callback is triggered on search.
State management
Uncontrolled / onSearch
When you only need to capture the searched value, simply use the onSearch prop.
Note: Whether using controlled or uncontrolled, onSearch is always triggered on search.
Controlled / onInputChange
When you need to store the current state of the input, use the onInputChange prop. This callback will be triggered on every input change, including on the type-ahead variant when navigating with arrow keys or clicking an option from the drop-down menu.
As a second argument, the callback will receive an inputChangeType parameter that designates the type of change that occurred. This can be useful when calling an API to fetch results based on the search term and you need to differentiate between types of user interaction.
The inputChangeType parameter can have the following values. These values are available as constants via import { SearchInputChangeTypes } from '@uhg-abyss/web/ui/SearchInput';:
| Type | Description |
|---|---|
InputChange | User manually typed in the input field |
InputClear | User cleared the input using the clear button |
ArrowNavigation | User navigated with arrow keys |
ItemClick | User clicked on an item in the dropdown |
Note: SearchInput no longer captures a drop-down menu selection separately from changes to the search input field. Therefore, to simplify operations, the onChange prop has been removed in favor of solely utilizing onInputChange.
Display properties
Label
The label prop is required. The hideLabel prop can be set to true to hide the label visually, but still allow it to be accessible to screen readers.
Helper
Use the helper prop to display a help icon next to the label. Simply passing a string value will render the default helper, a Tooltip containing that string. The helper can be customized by passing in a node. It is recommended to use either a Tooltip or a Popover. See When should I use a Tooltip vs. a Popover? for more information on best practices regarding the two.
Placeholder
Use the placeholder prop to set the placeholder text.
Width
Use the width prop to set the width of the select list.
Search button variant
Use the searchButtonVariant prop to set the style variant of the search button icon when using the default search variant. Options are filled (default) and outlined.
Interactivity
onSearch
Use the onSearch prop to capture the searched value. The callback will receive the selected search term string as the first argument, and if applicable when using type-ahead, as a second argument, the entire object of the selected option.
A search occurs with the following actions:
- Pressing "Enter" when focused on the input field.
- Selecting an option from the drop-down menu.
- Clicking or pressing "Enter" on the default variant's search button.
Clearable
Use the isClearable prop to allow for clearing the search input. If true, a clear button will appear in the input. The optional onClear callback prop can be used to trigger additional actions when the clear button is clicked.
Open on focus
By default, the menu will automatically open when the input receives keyboard focus. To change this behavior, set the openOnFocus prop to false.
Note: By default, the menu will automatically open when clicked.
Enable outside scroll
Set the enableOutsideScroll prop to true to enable scrolling outside the search input component while the option list is open. Default is set to false.
Search filtering
Fuse.js
SearchInput uses the Fuse.js library to fuzzy filter results. What is fuzzy searching?... Generally speaking, fuzzy searching (more formally known as approximate string matching) is the technique of finding strings that are approximately equal to a given pattern (rather than exactly).
Fuse keys
The keys prop allows you to specify the values from the specific keys within your options object to search against. This feature accommodates nested paths, prioritizes certain fields with weighted search, and can handle searches within arrays of objects. The default search keys are ['label', 'value'].
For example, if the options contained objects with the following structure:
{value: "react",label: "React",tags: ['jsx', 'virtual dom', 'facebook']}and you wanted to allow users to search on the label and tag values, you would provide the following, as in the example below:
searchConfig={{ keys: ['label', 'tags'] }}Custom Fuse configurations
The Fuse configuration can be customized by following the Fuse documentation and passing the configurations into the searchConfig prop.
For example, if you wanted to adjust the threshold to 0, thus requiring an exact match, you would pass in the following object. The default threshold is 0.1.
Common config props:
keys: Array of keys to search againstthreshold: Threshold for fuzzy searchmaxResults: Maximum number of results to returndebounce: Debounce time in milliseconds
const customFuseConfig = { threshold: 0, // exact match};Highlighted search results
By default, highlightMatches is true and matching text in search results is highlighted with bold font weight and a yellow background color.
The highlightMatches prop accepts either a boolean or an object:
// Boolean usagehighlightMatches: boolean
// Object usagehighlightMatches: { fuzzyHighlighting?: boolean; colorHighlighting?: boolean;}fuzzyHighlighting: Uses Fuse.js match indices for precise character-level highlightingcolorHighlighting: Set tofalseto remove yellow background but keep bold font weight
To completely disable highlighting, set highlightMatches to false.
API filtering with debounce
To override the Fuse filtering and make asynchronous calls to an API to set the list of dropdown options, use a combination of the onInputChange and options props.
While searching, onInputChange will supply the current search value and whether the input field was updated due to a selection. After retrieving the option items from the API, pass them into the options prop.
To incorporate debouncing into the search, use the useDebounce hook.
import { useDebounce } from '@uhg-abyss/web/hooks/useDebounce';Note: Unlike SelectInput, the usage of onInputChange within SearchInput does not assume filtering will be handled externally, so you'll have to set searchConfig to false to prevent internal Fuse filtering.
This example shows all of these concepts together. The apiFilter function is called on every keystroke, but the API call is debounced to only occur after 300ms of inactivity. Search "united" to see the API call in action.
Menu option configurations
Options
Use the options prop to supply the drop-down menu options that will be available for selection. options is an array of objects, where each object has a base that includes the following properties:
value: unique identifier for the optionlabel: content the option will display within the menu list
[ { value: 'id1', label: 'Option 1' }, { value: 'id2', label: 'Option 2' }, { value: 'id3', label: 'Option 3' }, ...]Sections can also be specified. See Section headers for more details.
ValueKey / labelKey
If your data structure uses different property names than value and label, you can map them using the valueKey and labelKey props without restructuring your data.
valueKey: Specifies which property to use as the option's value (defaults to"value")labelKey: Specifies which property to use as the option's display text (defaults to"label")
This is particularly useful when working with API responses or existing data structures that can't be easily transformed.
Option list height
Use the maxListHeight prop to set the maximum height the option list can be before it becomes scrollable. The default value is 185px.
Section headers
To group list items under section headers, pass objects into the options array that have the section and items properties. section specifies the name of the section, which will be bolded and unselectable, while items contains the options within that section (with the same value/label format as normal), which will appear indented.
To retain section headers after searching with isSearchable, set retainSectionHeader within searchConfig to true.
[ { value: 'id1', label: 'Option 1' }, { value: 'id2', label: 'Option 2' }, { section: 'Section Header', items: [ { value: 'id3', label: 'Sub-section Option 1' }, { value: 'id4', label: 'Sub-section Option 2' }, ... ], }, ...]Custom render
Use the customRender prop to customize the render of each option item. If section headers are used, they will also be handled by this function. customRender provides the item object as the first parameter and the item's state as the second.
Virtualization
Use the virtual prop to add virtualization and improve performance when working with larger data sets. Virtualization leverages the useVirtualization hook, which utilizes the TanStack Virtual library. Setting virtual to true will utilize the default configuration. virtual also accepts an object to configure the virtualizer. To see all available values that may be provided to the virtual prop, please refer to the TanStack Virtual documentation.
To maximize performance, virtualization for the SearchInput component is configured by default to use fixed sizing based on an option item element height of 38px. If your item height remains fixed but is different from the default, utilize the estimateSize function. If the item height is unknown prior to rendering, enable dynamic sizing by setting dynamicSizing to true.
The default settings used in SearchInput are as follows:
estimateSize: Sets item height when using fixed sizing. When using dynamic sizing, to help with scroll performance, set this to the largest possible height of the item elements (default value is38).dynamicSizing: Whentrue, each option item element is dynamically measured on render. Scrolling performance may not be as smooth when using this prop (default value isfalse).overscan: The number of element items to render above and below the visible area (default value is5).
Additional Examples
Note: The following examples demonstrate common search interface patterns that would typically integrate with API endpoints to fetch real-time data. These examples use static mock data to showcase the component's flexibility in creating various layouts and interactions, rather than replicating full backend functionality.
SearchInput (Default) Props
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
className | string | - | - | CSS class name to apply to each element within the component |
css | Abyss.CSSProperties | Partial<Record<`abyss-${T}`, Abyss.CSSProperties>> | - | - | Object containing CSS styling to apply; uses the classes listed in the "Integration" tab of the component's documentation |
data-testid | string | - | - | Suffix used to create a unique ID used for automated testing |
disableDefaultProviderProps | boolean | false | - | If set to true, the component will not use the DefaultPropsProvider values. If you aren’t using the DefaultPropsProvider, this prop can be ignored. |
helper | React.ReactNode | - | - | Helper element next to label |
hideLabel | boolean | false | - | If true, the label will be visually hidden |
isClearable | boolean | - | - | If true, the input will display a clear button |
isTypeAhead | boolean | false | - | Enables typeahead functionality. |
label | string | - | The label for the input | |
onBlur | React.FocusEventHandler<HTMLInputElement> | - | - | Callback function executed when the input is blurred |
onClear | () => void | - | - | Callback function executed when the input is cleared |
onFocus | React.FocusEventHandler<HTMLInputElement> | - | - | Callback function executed when the input is focused |
onInputChange | (inputValue: string) => void | - | - | Callback fired every time the input value changes |
onKeyDown | (event: React.KeyboardEvent<HTMLElement>) => void | - | - | Callback fired every time a key is pressed within search input |
onPaste | (event: React.ClipboardEvent<HTMLElement>) => void | - | - | Callback fired every time a paste event occurs within search input |
onSearch | (inputValue: string) => void | - | - | Callback fired when user performs a search |
placeholder | string | - | - | Placeholder text for the input |
searchButtonVariant | "filled" | "outlined" | 'filled' | - | Variant of the search icon button |
value | string | - | - | Selected option value |
width | string | number | '100%' | - | Width of the input. |
SearchInput (Type-Ahead) Props
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
className | string | - | - | CSS class name to apply to each element within the component |
css | Abyss.CSSProperties | Partial<Record<`abyss-${T}`, Abyss.CSSProperties>> | - | - | Object containing CSS styling to apply; uses the classes listed in the "Integration" tab of the component's documentation |
customLoader | React.ReactElement<any, string | React.JSXElementConstructor<any>> | - | - | Custom loader node display when isLoading is true |
customRender | (item: SearchInputTypeAheadMenuOption | SearchInputTypeAheadMenuSection, itemState: Omit<...>) => React.ReactElem... | - | - | A custom render function for rendering each option |
data-testid | string | - | - | Suffix used to create a unique ID used for automated testing |
disableDefaultProviderProps | boolean | false | - | If set to true, the component will not use the DefaultPropsProvider values. If you aren’t using the DefaultPropsProvider, this prop can be ignored. |
enableOutsideScroll | boolean | false | - | Enable outside scroll when the select input is open. |
helper | React.ReactNode | - | - | Helper element next to label |
hideLabel | boolean | false | - | If true, the label will be visually hidden |
highlightMatches | boolean | { fuzzyHighlighting?: boolean | undefined; colorHighlighting?: boolean | undefined; } | true | - | Determines if the search matches should be highlighted. Can be a boolean or an object with advanced highlighting options. |
isClearable | boolean | - | - | If true, the input will display a clear button |
isLoading | boolean | false | - | Whether the input is loading. |
isTypeAhead | boolean | false | - | Enables typeahead functionality. |
label | string | - | The label for the input | |
labelKey | string | 'label' | - | Key for the label in the options. |
maxListHeight | string | number | '200px' | - | Maximum height for the list. |
onBlur | React.FocusEventHandler<HTMLInputElement> | - | - | Callback function executed when the input is blurred |
onClear | () => void | - | - | Callback function executed when the input is cleared |
onFocus | React.FocusEventHandler<HTMLInputElement> | - | - | Callback function executed when the input is focused |
onInputChange | (inputValue: string, changeType: SearchInputChangeType) => void | - | - | Callback fired every time the input value changes |
onKeyDown | (event: React.KeyboardEvent<HTMLElement>) => void | - | - | Callback fired every time a key is pressed within search input |
onOpenChange | (isOpen: boolean) => void | - | - | Callback fired when the dropdown menu opens or closes |
onPaste | (event: React.ClipboardEvent<HTMLElement>) => void | - | - | Callback fired every time a paste event occurs within search input |
onSearch | (inputValue: string, selectedOption: Record<string, any>) => void | - | - | Callback fired when user performs a search |
openOnFocus | boolean | true | - | Whether the menu should open when the input receives focus. |
options | (SearchInputTypeAheadMenuOption | SearchInputTypeAheadMenuSection)[] | - | - | Options for the select input. |
placeholder | string | - | - | Placeholder text for the input |
searchConfig | false | SearchConfig | - | - | Configuration for the search. When set to false, disables internal filtering. |
value | string | - | - | Selected option value |
valueKey | string | 'value' | - | Key for the value in the options. |
virtual | boolean | VirtualConfig | - | - | Adds virtualization to option item drop-down list. Can be a boolean or object with additional virtual scrolling configurations. |
width | string | number | '100%' | - | Width of the input. |
SearchInput Classes
| Class Name | Description |
|---|---|
| .abyss-search-input-root | SearchInput root element |
| .abyss-search-input-wrapper | Wrapper for all non-portal/menu elements |
| .abyss-search-input-label | SearchInput label |
| .abyss-search-input-container-wrapper | Wrapper for selection container interior elements |
| .abyss-search-input | SearchInput input field |
| .abyss-search-input-type-ahead-search-icon-container | Container for the typeahead search icon |
| .abyss-search-input-type-ahead-search-icon | Typeahead search icon |
| .abyss-search-input-default-focus-wrapper | Wrapper to handle focus for default variant |
| .abyss-search-input-clear-button | Button to clear selection |
| .abyss-search-input-default-search-icon-container | Container for the default search icon |
| .abyss-search-input-default-search-icon | Icon for the default search icon |
| .abyss-search-input-portal-container | Portal container for typeahead menu |
| .abyss-search-input-dismissable-layer | Dismissable layer for typeahead menu |
| .abyss-search-input-menu-container | Container for the typeahead menu |
| .abyss-search-input-menu-loading-container | Container for the loading spinner in the typeahead menu |
| .abyss-search-input-menu-top-container | Container for the custom top slot content in the typeahead menu |
| .abyss-search-input-menu-bottom-container | Container for the custom bottom slot content in the typeahead menu |
| .abyss-search-input-menu-loading-spinner | Loading spinner in typeahead menu |
| .abyss-search-input-menu-virtual-wrapper | Wrapper for virtualized menu items |
| .abyss-search-input-menu-option-list-container | Container for all options in typeahead menu |
| .abyss-search-input-menu-section-list | List of section options in typeahead menu |
| .abyss-search-input-menu-option-heading | Section heading in typeahead menu |
| .abyss-search-input-menu-option | Individual selectable option in typeahead menu |
| .abyss-search-input-menu-option-search-icon | Search icon in typeahead menu option |
| .abyss-search-input-menu-option-label | Typeahead menu option label content |
| .abyss-search-input-menu-option-heading-label | Typeahead menu option heading label content |
A combobox is a widget made up of the combination of two distinct elements: 1) a single-line textbox, and 2) an associated pop-up element for helping users set the value of the textbox. The popup may be a listbox, grid, tree, or dialog. Many implementations also include a third optional element -- a graphical button adjacent to the textbox, indicating the availability of the popup. Activating the button displays the popup if suggestions are available.
Adheres to the Combobox WAI-ARIA design pattern. Example: Editable Combobox With Both List and Inline Autocomplete
Include meaningful accessible labels, even when not displayed
All SearchInput fields must include a meaningful label, even if hidden (using hideLabel). This should start with the word "Search", especially if there is any visible text that suggests that (such as placeholder="Search..."). If this is not possible or part of the design, use the I18nProvider to prepend "Search " to the aria-label (as shown in the second example below).
Typeahead Variant Keyboard Interactions
Textbox Keyboard Interactions
| Key | Description |
|---|---|
| Down Arrow | If the listbox is displayed: Moves focus to the second suggested value. Note that the first value is automatically selected. If the listbox is not displayed: opens the listbox and moves focus to the first value |
| Up Arrow | If the listbox is displayed, moves focus to the last suggested value. If the listbox is not displayed, opens the listbox and moves focus to the last value |
| Alt + Down Arrow | Opens the listbox without moving focus or changing selection |
| Enter | If the listbox is displayed and the first option is automatically selected: Sets the textbox value to the content of the selected option. Closes the listbox |
| Esc | Clears the textbox. If the listbox is displayed, closes it |
Listbox Keyboard Interactions
| Key | Description |
|---|---|
| Enter | Sets the textbox value to the content of the focused option in the listbox. Closes the listbox. Sets focus on the textbox |
| Esc | Closes the listbox. Sets focus on the textbox. Clears the textbox |
| Down Arrow | Moves focus to the next option. If focus is on the last option, moves focus to the first option |
| Up Arrow | Moves focus to the previous option. If focus is on the first option, moves focus to the last option |
| Right Arrow | Moves focus to the textbox and moves the editing cursor one character to the right |
| Left Arrow | Moves focus to the textbox and moves the editing cursor one character to the left |
| Home | Moves focus to the textbox and places the editing cursor at the beginning of the field |
| End | Moves focus to the textbox and places the editing cursor at the end of the field |
Component Tokens
Note: Click on the token row to copy the token to your clipboard.
SearchInput Tokens
| Token Name | Value | |
|---|---|---|
| search-input.color.border.menu | #CBCCCD | |
| search-input.color.surface.menu | #FFFFFF | |
| search-input.color.surface.menu-item.rest | #FFFFFF | |
| search-input.color.surface.menu-item.hover | #F3F3F3 | |
| search-input.color.surface.menu-item.active | #E5E5E6 | |
| search-input.color.surface.search-button.filled.rest | #002677 | |
| search-input.color.surface.search-button.filled.hover | #004BA0 | |
| search-input.color.surface.search-button.filled.active | #00184D | |
| search-input.color.surface.search-button.outlined.rest | #FFFFFF | |
| search-input.color.surface.search-button.outlined.hover | #F3F3F3 | |
| search-input.color.surface.search-button.outlined.active | #E5E5E6 | |
| search-input.color.icon.search.filled | #FFFFFF | |
| search-input.color.icon.search.outlined | #323334 | |
| search-input.color.icon.search.content | #323334 | |
| search-input.color.icon.search.menu-item | #002677 | |
| search-input.color.text.menu-item | #002677 | |
| search-input.border-radius.all.menu | 4px | |
| search-input.border-width.all.menu | 1px | |
| search-input.sizing.icon.menu-item | 20px | |
| search-input.spacing.gap.horizontal.menu-item | 8px | |
| search-input.spacing.padding.horizontal.menu.loading | 16px | |
| search-input.spacing.padding.horizontal.menu-item | 16px | |
| search-input.spacing.padding.vertical.menu-item | 8px | |
| search-input.spacing.padding.top.menu.loading | 16px | |
| search-input.spacing.padding.bottom.menu.loading | 24px | |
| search-input.elevation.menu | 0px 2px 4px -2px rgba(0,0,0,0.16) |