Version 0.12.0

SearchAutocomplete

A search input with an accessible results dropdown.

Usage#

import { SearchAutocomplete, SearchAutocompleteItem } from '@backstage/ui';

<SearchAutocomplete
  inputValue={inputValue}
  onInputChange={setInputValue}
>
  {items.map(item => (
    <SearchAutocompleteItem key={item.id} id={item.id} textValue={item.name}>
      {item.name}
    </SearchAutocompleteItem>
  ))}
</SearchAutocomplete>

API reference#

SearchAutocomplete#

PropTypeDefaultDescription
aria-label
string
-Accessible label for the search input.
aria-labelledby
string
-ID of the element that labels the search input.
inputValue
string
-The current input value (controlled).
onInputChange
(value: string) => void
-Handler called when the input value changes.
placeholder
string
SearchPlaceholder text shown when the input is empty. Also used as the accessible label when neither aria-label nor aria-labelledby is provided.
size
smallmedium
smallVisual size of the input. Use small for inline or dense layouts, medium for standalone fields.
isLoading
boolean
falseWhether results are currently loading. Dims existing results and announces loading state to screen readers.
popoverWidth
string
-Width of the results popover. Accepts any CSS width value. Matches the input width when not set.
popoverPlacement
bottom startbottom endtop starttop end
bottom startPlacement of the results popover relative to the input.
defaultOpen
boolean
falseWhether the results popover is open by default.
children
ReactNode
-The result items to render inside the autocomplete.
className
string
-Additional CSS class name for custom styling.
style
CSSProperties
-Inline CSS styles object.

Inherits all React Aria Autocomplete props.

SearchAutocompleteItem#

Individual result item within the autocomplete list.

PropTypeDefaultDescription
id
string
-Unique identifier for the item.
textValue
string
-Plain text value used for keyboard navigation and accessibility.
onAction
() => void
-Handler called when the item is selected.
children
ReactNode
-Content to render inside the item.
className
string
-Additional CSS class name for custom styling.

Examples#

With rich content#

Here's a view when items include a title and description.

const fruits = [
  { id: 'apple', name: 'Apple', description: 'A round fruit' },
  { id: 'banana', name: 'Banana', description: 'A yellow curved fruit' },
  { id: 'cherry', name: 'Cherry', description: 'A small red stone fruit' },
];

function Example() {
  const [inputValue, setInputValue] = useState('');

  const filtered = fruits.filter(fruit =>
    fruit.name.toLowerCase().includes(inputValue.toLowerCase()),
  );

  return (
    <SearchAutocomplete
      placeholder="Search fruits..."
      inputValue={inputValue}
      onInputChange={setInputValue}
    >
      {filtered.map(fruit => (
        <SearchAutocompleteItem
          key={fruit.id}
          id={fruit.id}
          textValue={fruit.name}
        >
          <Text weight="bold">{fruit.name}</Text>
          <Text variant="body-small" color="secondary">
            {fruit.description}
          </Text>
        </SearchAutocompleteItem>
      ))}
    </SearchAutocomplete>
  );
}

In header#

Use popoverWidth to control the dropdown width when placed in constrained layouts like PluginHeader.

Title

<PluginHeader
  title="Title"
  customActions={
    <>
      <SearchAutocomplete
        size="small"
        inputValue={inputValue}
        onInputChange={setInputValue}
        popoverWidth="400px"
      >
        {filtered.map(fruit => (
          <SearchAutocompleteItem
            key={fruit.id}
            id={fruit.id}
            textValue={fruit.name}
          >
            {fruit.name}
          </SearchAutocompleteItem>
        ))}
      </SearchAutocomplete>
    </>
  }
/>

With selection#

Use onAction on items to handle selection and reset the input.

Last selected: none
function Example() {
  const [inputValue, setInputValue] = useState('');
  const [selected, setSelected] = useState<string | null>(null);

  const filtered = fruits.filter(fruit =>
    fruit.name.toLowerCase().includes(inputValue.toLowerCase()),
  );

  return (
    <Flex direction="column" gap="4">
      <SearchAutocomplete
        placeholder="Search fruits..."
        inputValue={inputValue}
        onInputChange={setInputValue}
      >
        {filtered.map(fruit => (
          <SearchAutocompleteItem
            key={fruit.id}
            id={fruit.id}
            textValue={fruit.name}
            onAction={() => {
              setSelected(fruit.name);
              setInputValue('');
            }}
          >
            {fruit.name}
          </SearchAutocompleteItem>
        ))}
      </SearchAutocomplete>
      <Text>Last selected: {selected ?? 'none'}</Text>
    </Flex>
  );
}

Theming#

Our theming system is based on a mix between CSS classes, CSS variables and data attributes. If you want to customise this component, you can use one of these class names below.

  • bui-SearchAutocomplete
  • bui-SearchAutocompleteSearchField
  • bui-SearchAutocompleteInput
  • bui-SearchAutocompleteClear
  • bui-SearchAutocompletePopover
  • bui-SearchAutocompleteInner
  • bui-SearchAutocompleteListBox
  • bui-SearchAutocompleteLoadingState
  • bui-SearchAutocompleteEmptyState

Theming#

Our theming system is based on a mix between CSS classes, CSS variables and data attributes. If you want to customise this component, you can use one of these class names below.

  • bui-SearchAutocompleteItem
  • bui-SearchAutocompleteItemContent

Changelog#