Skip to main content
Official government website

Combobox

Lets users type to filter a long list and choose one option.

Examples
HTML and React
Group
Form elements
On this page

Preview

Combobox with hint text
Open in new tab

options maps to <option> elements; <option> children work too. The value, defaultValue and onChange props belong to the underlying select, exactly as on Select.

The Combobox component is a text input that filters a long list of options as the user types, then lets them choose one. It is a progressive enhancement of a native <select>: without JavaScript users get the select, and with it the select stays in the form, so the chosen value still submits under the same name and the visible labels can keep mapping to whatever values the service needs. The same enhancement also works over a plain text input, offering suggestions for free text: see Free text with suggestions.

Usage

When to use

  • Use a combobox for one choice from a long list users already know the answer to, such as a country, a school or an occupation, where scrolling a select would be slow.
  • Use it when the answer must stay one of the options, for example because each label maps to a code or an address the service relies on.

When not to use

  • Do not use it for a short list: radio buttons show every option, and a select handles a familiar list of a dozen or so.
  • Do not use it for an answer that is not on the list. If users may need to type something new, use an input.

Best practices

Keep the options in the select

The options live in the <select>, so the same markup serves users with and without JavaScript and the server validates one submitted value. Start the list with a non-selectable placeholder option such as “Select a country” so nothing is chosen by default. Initialise the HTML enhancement with initAll() from @govtech-bb/frontend; the React component enhances itself.

Tell users they can type

Add hint text such as “Start typing to filter the list”. The field looks like a text input, and the list opens as soon as the user types or clicks into it, so users who recognise their answer more easily than they recall it can still browse the whole list.

Write labels the way users type them

Filtering matches anywhere in an option’s label, ignoring case and accents, so “lucia” finds “Saint Lucia”. Keep labels unique and spell them out in full rather than abbreviating.

How it works

The enhancement keeps the <select> in the form but hides it from assistive technology and the tab order, and adds:

  • a text input with role="combobox", which takes over the select’s id so the label, hint and error message stay connected. It carries aria-expanded, aria-controls pointing at the list and aria-autocomplete="list";
  • the list, a role="listbox" named by the field’s label, holding one role="option" per matching choice. Focus never leaves the input: aria-activedescendant names the highlighted option, which is also marked aria-selected. The option currently chosen is shown bold;
  • a visually hidden status region that announces how many options match.

Keyboard support:

  • Type to filter. Click or tap the field to see the whole list.
  • Down and Up arrow open the list and move the highlight, wrapping at the ends and skipping disabled options.
  • Enter chooses the highlighted option. With nothing highlighted it closes the list rather than submitting the form.
  • Escape closes the list and leaves the value as it was.
  • Tab, or clicking elsewhere, closes the list. Text that exactly matches an option chooses it, an emptied field clears the choice, and anything else reverts to the chosen option, so the select never holds a value that is not one of its options.

Change the text shown when nothing matches with data-empty-label on the .govbb-combobox wrapper, or the emptyLabel prop in React. The default is “No results found”.

Choosing an option fires input and change on the select, then a bubbling govbb-combobox-select event on the wrapper whose detail holds the option’s index, value and label.

Free text with suggestions

When the answer does not have to be one of the options, wrap a text input and a <datalist> instead of a select. The input keeps carrying the value, and whatever options the page puts in the datalist are offered as suggestions: shown as they are, not filtered, so a lookup service simply rewrites the datalist as results arrive and the list follows. Without JavaScript the browser’s own datalist suggestions apply. This is the shape for an address lookup or a search box; GOV.UK calls this pattern an autocomplete.

Free text with suggestions
Open in new tab

Each suggestion has a value, which the field takes when it is chosen, and an optional label to show in the list instead, for example a full formatted address for a value that is just its first line. onSuggestionSelect receives the chosen suggestion and its index after onChange, which is where a form fills in related fields such as the parish or coordinates. In HTML, listen for the govbb-combobox-select event and read the <option>’s attributes.

The list only opens once the user has typed something, and closes when the datalist is empty: no “No results found” row, because the typed text is a valid answer on its own. Enter with nothing highlighted submits the form as it would in any text input.

Inline list

Add govbb-combobox--inline to the wrapper, or inline in React, to put the list in the page flow beneath the field instead of floating it over what follows: the content below moves down while the list is open, so nothing is covered. The inline list has no height cap and never scrolls, so cap the suggestions yourself. This is how search with suggestions uses it.

Errors

When a combobox fails validation, show an error message (.govbb-error-message) above the field with role="alert", and mark the select with aria-invalid="true" and aria-describedby pointing at the error message id. The enhancement copies both onto the input. Keep error messages specific and actionable, such as “Enter and select a country”.

Combobox with error
Open in new tab