Add a new combo box component with auto-complete.
Review Request #15213 — Created July 31, 2026 and updated — Latest diff uploaded
This introduces
Ink.ComboBox, a text field with a pop-up listbox of
auto-complete suggestions, intended to replace the legacy
rbautocompleteplugin and Selectize-based related-object selectors. It
implements the ARIA 1.2 combobox pattern: DOM focus stays on the text
field (anInk.TextField), the pop-up is a role="listbox", and the
highlighted option is tracked virtually through aria-activedescendant on
the input.Suggestions can come from a static set of items (via an "items" option
orInk.ComboBox.Itemchildren, filtered client-side) or from an
asynchronous "load" function suitable for API-backed lookups. Async
queries are debounced, stale responses are discarded, and loading,
empty, and error states are shown in a status area within the pop-up.Items are backed by a new
ComboBoxItemmodel and
ComboBoxItemsCollection. Options render a label and optional
description by default, with arenderItemhook for fully custom
content (such as avatars).Three selection modes are supported:
-
Single selection (the default), with the selected item exposed as
"value" and serialized to an optional hidden form input via "name". -
Multiple selection, showing selected items as removable token pills
within the field, tracked in aselectedItemscollection that can be
pre-populated or shared. Selected items are excluded from suggestions,
Backspace on an empty field removes the last token, and the hidden
input serializes comma-separated item IDs (matching Djblets'
related-object widgets). The token list is styled like the text field,
keeping a stable height as tokens are added. -
Multiple selection with a consumer-rendered list, where the selection
is tracked and serialized but rendered by the consumer (such as rows
with avatars below the field), by listening to events on
selectedItems. This can replace Djblets' Selectize-based
RelatedObjectSelectorView.
There's an optional -is-joined state that allows improving the
rendering in this mode, joining the search box directly to the list of
selected results.
Keyboard behavior is designed to feel familiar to users of the legacy
rbautocomplete fields: Arrow keys open the pop-up and move the
highlight with wrapping; PageUp/PageDown jump to the first/last option;
Enter, Tab, and (in multiple mode) comma accept the highlighted option,
with Tab keeping focus in the field so the completion can be seen and
further values typed; Escape closes the pop-up and then clears the
field. Enabling selectFirst reproduces the legacy
tab-completes-the-first-result flow, and a hintText option shows a
hint (such as "Press Tab to auto-complete.") below the results.
In single-selection mode, editing the text away from an accepted item
clears the selection. Otherwise "value" and the hidden input would keep
reporting an item the field no longer shows, and the form would submit
something the user never chose.
Disabling the combo box disables the whole control. In multiple mode
that includes the token remove buttons, which are separate controls from
the field, and the token list draws the disabled state since it holds
the chrome in that mode.
The status strings for the loading, empty, and error states can be
replaced through the "loadingText", "noResultsText", and "errorText"
options, so consumers can pass translated text in.
- Ran unit tests covering filtering, keyboard navigation and completion,
mouse interaction, debouncing, stale-response discarding, error
states, all three selection modes, serialization, events, selection
staleness, disabled behavior, and custom status text. - Verified interactively in Chrome and Firefox: typing, Tab/comma
completion with focus retention, ARIA attribute placement, and stable
field height with tokens, in both single and multiple modes. - Added storybook entries for static, async, error, tab-completion,
multiple, and consumer-rendered-list configurations. Verified in both
light and dark mode.