Combobox
Search and select one or several typed options while keeping query and selection state separate.
Search and select one or several typed options with query and selection state kept separate.
Contract
| Axis | Contract |
|---|---|
| State | The query and the selected value are separate axes. TRComboboxController owns the value plus the TextEditingController and FocusNode; TRCombobox.controlled hands the value back to you while the controller keeps the query. |
| Field | The field is a TRTextField, so label, placeholder, helperText, errorText, uiSize, and width behave exactly as they do there. clearable adds a clear button in the trailing slot once the field holds a query or a selection. |
| Layer size | layerSize is independent from the field width. The complete options layer matches its anchor and grows with content up to TRMeasurements.measureXl high by default. |
| Filtering | optionsBuilder decides the candidates and filterMode narrows them: contains, startsWith, or none. A filter callback overrides filterMode. Use none when a remote or asynchronous optionsBuilder is already authoritative. |
| Multiple | TRMultiCombobox renders committed values as removable chips above the field and clears the query after each pick. layout: TRComboboxLayout.grid lays the popup out in two columns instead of a list. |
| Interaction | Arrow keys move the highlight, Enter commits it, and Escape closes the popup. autoHighlight decides whether Enter can commit the first match before any arrow key. Options with enabled: false stay visible, render muted, and are skipped by both Enter and arrow navigation. |
| Forms | TRComboboxFormField and TRMultiComboboxFormField are FormField subclasses, so validator, onSaved, autovalidateMode, and Form.reset work as usual and errorText is supplied by the field state. |
Reach for a combobox when the option list is long enough that typing beats scrolling but the committed value must still come from that list. Use TRSelect for a short fixed list, and TRAutocomplete when free text the user typed is itself a valid answer.
Install
Add the package, then import its public library.
flutter pub add tinyrack_uiimport 'package:tinyrack_ui/tinyrack_ui.dart';Playground
Usage
import 'package:material_ui/material_ui.dart';
import 'package:tinyrack_ui/tinyrack_ui.dart';
TRCombobox<String>(
label: 'Channel',
placeholder: 'Choose a channel',
items: const [
TRComboboxItem(value: 'stable', label: 'Stable'),
TRComboboxItem(value: 'beta', label: 'Beta'),
],
onValueChange: selectChannel,
)Examples
Filter and commit one rack permalink
Typing narrows the popup while the committed value stays separate from the query. Selecting a rack writes its label back into the field.
Sizes permalink
Pass uiSize to align the combobox with neighboring TRTextField, TRSelect, or TRButton heights.
Selected and disabled options permalink
An option with enabled set to false stays in the popup so the reason it is unavailable remains visible. It renders muted and both Enter and arrow navigation skip it.
Filter semantics permalink
Compare contains, startsWith, and no built-in narrowing. Use none when an asynchronous optionsBuilder already returns the matches it wants shown.
Multiple chips and grid popup permalink
TRMultiCombobox renders committed values as removable chips and clears the query after each pick. The grid layout fits short labels into two columns.
Required option and recovery permalink
TRComboboxFormField reports its error through errorText and clears it as soon as a value is committed, so the reader can recover without submitting again.
Controlled state and a custom filter permalink
The controlled constructor hands the value back to the caller while the controller keeps the query. A filter callback replaces filterMode when the built-in rules are not enough.
Popup width and layering permalink
Flutter has no portal or positioner parts. The popup opens on the combobox layer and takes its width from the field, or from the small overlay width token when width is left unset.
Keyboard selection permalink
With autoHighlight off, Enter commits nothing until an arrow key highlights a row. The clear button returns focus to the field so the popup stays open.
Single and multiple fields permalink
The FormField variants keep query text separate from typed selections and participate in validation, save, and reset.
API
TRCombobox properties
| Prop | Type / default | Purpose |
|---|---|---|
items | List<TRComboboxItem<T>> · const [] | Supplies the option source. Either items or optionsBuilder must be non-empty. |
optionsBuilder | TRComboboxOptionsBuilder<T>? · null | Returns candidates for a query, synchronously or as a Future. Its result is still narrowed by filterMode unless that is none. |
filterMode | TRComboboxFilterMode · contains | Matches option labels case-insensitively with contains or startsWith, or skips narrowing with none. Comparison uses toLowerCase, so it is not accent-insensitive the way the React useFilter collator is. |
filter | TRComboboxFilter<T>? · null | Replaces filterMode with a custom predicate. The query it receives is already trimmed and lower-cased. |
autoHighlight | bool · true | Keeps the first match armed so Enter commits it immediately. Set it to false to require an arrow key first. It defaults to true here because the underlying RawAutocomplete always keeps a valid highlight index, unlike the React default. |
clearable, clearSemanticLabel | bool · false, String · 'Clear' | Shows a clear button while the field holds a query or a selection. Clearing empties the query, reports null through onValueChange, and returns focus to the field. |
controller, defaultValue, value | TRComboboxController<T>?, T?, T? | Chooses the state model. defaultValue seeds the uncontrolled constructor, value is required by TRCombobox.controlled, and a controller can be shared with either. |
onQueryChange, onValueChange | ValueChanged<String>?, ValueChanged<T?>? | Report query edits and committed selections separately. onValueChange also fires with null when the clear button is used. |
layout | TRComboboxLayout · list | Draws the popup as a single-column list or a two-column grid. |
enabled, readOnly | bool · true, bool · false | Disable interaction, or keep a focusable field whose query cannot be edited. Both hide the clear button. |
label, placeholder, helperText, errorText | String? · null | Describe the field and its validation state through the underlying TRTextField. |
uiSize, width | TRUiSize · TRUiSize.md, double? · null | Set the control size and an optional fixed field width. Use layerSize for the popup. |
layerSize | TRLayerSize · match anchor / content height ≤ measureXl | Sizes the complete options layer for single, multiple, and FormField variants. |
TRMultiCombobox properties
| Prop | Type / default | Purpose |
|---|---|---|
defaultValue, value | List<T> · const [], List<T>? | Hold the committed values. value is required by TRMultiCombobox.controlled and makes the widget fully controlled. |
onValueChange | ValueChanged<List<T>>? · null | Reports the full selection after every pick, chip removal, or clear. Selecting an already selected value removes it. |
controller | TRMultiComboboxController<T>? · null | Owns the values and the shared query field. Its clear resets the values only, so clear the textEditingController too when driving it directly. |
Items and enums
| Prop | Type / default | Purpose |
|---|---|---|
TRComboboxItem.value, label | T · required, String · required | Carry the typed value and the text shown in the popup and written back into the field on commit. |
TRComboboxItem.enabled | bool · true | Marks an option as unselectable. It stays in the popup, renders with the muted text color, and is skipped by keyboard navigation. |
TRComboboxItem.leading, trailing | Widget? · null | Place icons on either side of the option label. |
TRComboboxLayout | list, grid | Selects the popup arrangement. grid uses two columns of fixed-height rows. |
TRComboboxFilterMode | contains, startsWith, none | Selects the built-in narrowing rule applied to the option source. |
Controllers and form fields
| Prop | Type / default | Purpose |
|---|---|---|
TRComboboxController | ChangeNotifier | Exposes value, select, and clear alongside the owned textEditingController and focusNode. Dispose it with the widget that created it. |
TRMultiComboboxController | ChangeNotifier | Exposes values, replace, toggle, and clear. values is an unmodifiable view, so replace the list instead of mutating it. |
TRComboboxFormField | FormField<T> | Participates in validation and save callbacks with a typed selected value, and feeds errorText back into the field. |
TRMultiComboboxFormField | FormField<List<T>> | Does the same for a list of values, so a validator can require at least one selection. |