<ComboBox>

Creates drop-down combined with an editable text-box. Also referred to as a typeahead or an autocomplete. Typing will suggest options which the user can then select.

This uses the ARIA 1.0 editable combo box design pattern.

Combo-boxes like this are used in multiple different ways with many different interaction patterns. This implementation is flexible and can be used, for example, as both a search autocomplete or to restrict select to a set of predefined options.

It supports loading options asynchronous and highlighting the matched text.

Usage

const [value, setValue] = useState(initialValue);
// Updates as the user types
const [search, setSearch] = useState(null);
// Filter the options using the search term
const filteredOptions = useTokenSearch(search, { options });

<label
  id="id-label"
  htmlFor="id"
>
  Label
</label>
<ComboBox
  id="id"
  // required so the listbox is properly labelled
  aria-labelledby="id-label"
  options={filterOptions}
  value={value}
  onValue={setValue}
  onSearch={setSearch}
/>

This is a controlled component. You must update value in response to onValue.

The onSearch function is called with the current search value and should be used to update the options.

Props

Display and selecting options

options: Array<any>

The options to display. See options.

mapOption: (option: any) => Option | string

Map an option into label, value, disabled and group. See options

value: any

The currently selected option

onValue: (option: any) => void

Called with the selected option when a user selects an option.

onSearch: (search: string) => void

Called as a user types.

If this isn't supplied the combo-box will be set to aria-autocomplete="none", otherwise it is a aria-autocomplete="list". See combo-box on ARIA practices.

busy: boolean

Used with an async search to say the component is currently busy. This sets aria-busy.

HTML attributes

id: string

Required The id of the component

classPrefix: string = "react-combo-boxes'

By default the component is built using BEM style class names. This sets the prefix for all those classes.

Set to falsey to remove the BEM classes.

className: string

Sets the class name on the wrapper only.

aria-describedby: string | string[]

Ids of any elements describing the combo-box.

aria-labelledby: string | string[]

Ids of any elements labelling the combo-box and the list-box

You should set this to the id of the label as ARIA requires the list-box to be named.

ref

The ref will be passed to the <input> element.

Additional HTML attributes

The following attributes will be passed to the <input> element.

Behaviour switches

managedFocus: boolean = true

When true, the document focus moves to the selected option. When false the selected option is exposed to a screen-reader by aria-activedescendant.

This defaults to true for maximum compatibility with older screen-readers.

autoselect: boolean | "inline" = false

If true the first matching option is automatically selected.

If "inline" then aria-autocomplete="inline" is set and the text typed into the combo-box is autocompleted.

See ARIA practices for an explanation of these modes.

clearOnSelect: boolean = false

If true, calls onSearch with an empty string when an option is selected. If false, onSearch is called with the selected label.

closeOnSelect: boolean = true

Close the listbox when an item is selected.

If set to false the list box will remain open and continue to show existing on new options to select.

expandOnFocus: boolean = true

Expand the list box when then component is focused. If false the use must type before the list box is expanded.

selectOnBlur: boolean = true

Select the currently focused option when blurring the component.

If false the user must explicitly select an option by pressing Enter or clicking on an option.

showSelectedLabel: boolean = false

If set to true, the value in the input will be updated to match the currently focused option.

tabAutocomplete: boolean = false

If true, pressing Tab while an autocompleted option is displayed will select it without moving the focus.

If false pressing Tab moves to the next focusable element. The option may still be selected if selectOnBlur is true.

tabBetweenOptions: boolean = false

If true, pressing Tab and Shift + Tab will move between options in the listbox.

This is against normal user interface guidelines but maybe preferable in some situations.

Customisation

assistiveHint

Sets the description of the combo-box.

Defaults to "When results are available use up and down arrows to review and enter to select"

notFoundMessage: () => string

Set the message to be displayed or read or a screen-reader when the no search options are found.

Defaults to: "No results found"

foundOptionsMessage: (options: Array<Option>) => string

Sets the message to be read to a screen-reader when options are found.

Defaults to: "x results are available"

selectedOptionMessage: (option: Option, options: Array<Option>) => string

Sets the message to be read to a screen-reader when an option is highlighted.

Defaults to: "label x of y is highlighted"

render props

A number of render methods are provided to customise the appearance of the component.

Each render method has the signature

(
  // The props set on the <ComboBox>
  props: object,
  // The state of the component
  state: {
    ['aria-autocomplete']: string;
    ['aria-busy']: string;
    // Is the list box open
    expanded: boolean;
    // Is the not found message showing
    notFound: boolean;
    // Current search string
    search: string;
    // Currently selected option
    currentOption: Option;
    // Suggested option if autocomplete is true
    suggestedOption: Option;
    // Current option (when rending an option)
    option: Option;
    // Is the current option selected (when rendering an option)
    selected: boolean;
    // Current group (when rendering a group or option)
    group: Group;
  },
  // The props passed into the component
  componentProps: object;
) => React.ReactNode

The render functions available are:

Name Default value Description
renderWrapper (props) => <div {...props} /> Renders the component wrapper
renderInput (props) => <input {...props} /> Renders the combo-box input
renderDownArrow (props) => <span {...props} /> Renders down arrow displayed when options are available
renderClearButton (props) => <span {...props} /> Renders '×' button displayed when an option is selected
renderListBox (props) => <ul {...props} /> Renders the list-box
renderGroup ({ key, ...props }) => <Fragment key={key} {...props} /> Wraps a group of options
renderGroupAccessibleLabel (props) => <span {...props} /> Renders the accessible label for a group. This will be read out before each option
renderGroupLabel (props) => <li {...props} /> Renders the group including the options. This will be ignored by a screen-reader
renderGroupName (props) => <Fragment {...props} /> Renders the name of the group. This will be ignored by a screen-reader
renderOption ({ key, ...props }) => <li key={key} {...props} /> Renders an option
renderValue (props) => <Fragment {...props} /> Renders the value within an option. See Highlighters.
renderNotFound (props) => <div {...props} /> Renders the not found message
renderAriaDescription (props) => <div {...props} /> Renders the assistive hint of the combo box

onLayoutListBox: (listbox: Element) => void | []<(listbox: Element) => void>

This is called whenever the listbox is displayed or the options change.

This can be used to position or resize the listbox.

See list box layout for some supplied layout helpers.