Skip to content
EspañolEnglish
All components (204)

Search field

Fields · SearchField

What it is and when to use it

The field with autocomplete: you type and the list is filtered as you go, ignoring accents and case. Every time the text changes, it announces how many options are left ("3 options"), which is what makes it usable without seeing the screen.

When to use it

  • Choosing from a long list: customers, products, suppliers.
  • serverFiltered when the search is done by the server: the already filtered list is passed in and onInputChange is listened to; loading while it arrives.
  • allowsCustomValue to keep something that is not in the list (a new supplier).
  • Each option can carry a second line (description), an icon and be disabled (disabled).

When not to

  • A short, closed list: Select. A dropdown of four options does not need a search field.
  • Choosing several: MultiSelect.
  • Searching for actions or screens of the application: CommandPalette.

Keyboard: focus always stays in the field, so you can keep typing. Down Arrow opens the list from the first option and Up Arrow from the last; the arrows move through it, Enter chooses and Tab closes the list and leaves. Escape closes the list and returns the text to what was chosen; leaving the field blank and exiting removes the choice. The arrow button opens the whole list with the mouse or a finger; it is not in the Tab order.

Accessibility: it is a combobox and the active option is announced from the field with aria-activedescendant. The label is required; the help and the error are read as the description. If what is typed finds nothing, the list does not close abruptly: it says "No results" (noResultsMessage). Disabled options are announced as such and cannot be chosen.

Fine-tuning: no variables of its own: the box uses those of the field (--amset-field-*) and is adjusted with the classes amset-search__group, amset-search__open and amset-search__panel; the list is the usual one (amset-listbox, amset-option).

What it looks like

Try "alv" or "jewelry": it works without accents too.

<SearchField
  label="Customer"
  placeholder="Enter the customer's name"
  noResultsMessage="No customers with that name"
  options={[
    { key: 'aurelia', label: 'Aurelia Jewelry', description: 'Madrid · 32 orders' },
    { key: 'bravo', label: 'Bravo Plateria', description: 'Cordoba · 9 orders' },
  ]}
  onSelectionChange={setCliente}
/>

Props

Import it with import { SearchField } from '@amset/ui'. Required props are marked.

PropTypeWhat it does
labelrequiredstring—
optionsrequiredreadonly ListOption[]—
allowsCustomValuebooleanLets a text that is not in the list be confirmed. Without it, on leaving the field the text goes back to the chosen option: a search box over a closed list cannot keep something that does not exist.
autoFocusboolean—
classNamestringMerged with the library classes; it does not replace them.
defaultInputValuestring—
defaultSelectedKeystring | nullThe key chosen at the start, without controlling it from outside.
disabledboolean—
errorstring—
hiddenLabelbooleanThe label for the screen reader only. For when the field sits inside something that already explains itself (a table cell, a group of filters), never to save space.
hintstring—
inputValuestringThe typed text, controlled from outside.
invalidboolean—
loadingbooleanThe options are arriving. Marks the field as busy, shows a ring and a `loadingText` row in the list; the options that were already there stay.
loadingTextstringWhat the loading row says. "Loading…" by default.
menuTrigger"input" | "focus" | "manual"What opens the list: `input` (the default) when typing, `focus` as soon as the field receives focus, and `manual` only with the button or the arrows.
namestringSo that the chosen key travels in a native form.
noResultsMessagestringText when what is typed finds nothing.
offsetnumberSeparation in pixels between the field and the list. By default, none.
onBlur() => voidOn leaving the field. The form uses it to mark that it has been touched.
onInputChange(text: string) => void—
onOpenChange(open: boolean) => voidWhen the list opens or closes.
onSelectionChange(key: string | null) => void—
placeholderstring—
placementPlacementWhere the list appears. By default, right below the field.
readOnlyboolean—
renderOptionOptionRender<ListOption>Paints the inside of each option in the list: an avatar, two lines, a price. The name the screen reader reads is still `label`.
requiredboolean—
selectedKeystring | nullThe chosen key, controlled from outside.
serverFilteredbooleanThe list already comes filtered from outside (server-side search). By default the component itself filters with what is typed.
size"sm" | "md" | "lg"—
validationBehavior"aria" | "native"—
variantFieldVariant—

It also accepts the attributes of the element it renders: className, style, data-*, aria-* and its events.

In the test bench

Every state and variant, to try one at a time, on its page at ui.amset.tech: