Skip to content

ComboBox

ComboBox combines a single-line editor with suggestions. It owns transient popup/highlight state; your application owns the complete TextEditingValue and the suggestion list.

#include <huxerui/huxerui.h>
#include <cstddef>
#include <string>
#include <vector>
using namespace huxerui;
[[huxerui::composable]]
View CityField() {
auto value = UseState(TextEditingValue::FromText(""));
const std::vector<std::string> cities{"Berlin", "Kyoto", "Lisbon"};
return ComboBox(value, cities)
.Label("City")
.OnChanged([value](const TextEditingValue& next) { value = next; })
.OnSelected([value](std::size_t, const TextEditingValue& next) { value = next; });
}

Typing emits OnChanged. Accepting a suggestion emits OnSelected(index, next_value) without also emitting OnChanged; handle both paths. Preserve the proposed selection and composition instead of reconstructing text-only values.

Supply the suggestions appropriate to the current query. The example deliberately offers a fixed short list; filtering, remote search, cancellation, and result ordering belong to the application.

ComboBox(value, suggestions, text_factory, content_factory) separates the accepted string from row presentation. The text factory returns the item’s editable text; the content factory returns its row View. Give changing rows stable keys and keep row content free of competing interactive controls.

Declared by <huxerui/view.h>. The value accepts TextEditingValue or State<TextEditingValue>. Suggestions are an input range: read a State-held collection in composition and pass the collection, not a second editor-owned data store.

  • Field configuration: Label, Placeholder, LeadingIcon, TrailingIcon, Variant, Align, MaxLength, Validation, and InputConfiguration.
  • EmptyContent(factory) supplies content when there are no suggestions.
  • OnSubmitted(void()) handles submission when it is not accepting an active suggestion.
  • OnExpandedChanged(bool) observes popup changes; it is not a controlled visibility property.
  • ComboBoxStyle owns theme appearance.

This is a single-line, non-secure editor. IME composition takes precedence over suggestion acceptance; do not intercept Enter blindly. For multiline or secure input use TextField; for a non-editable value use Select.

Operation Accepted value and behavior
Label, Placeholder StringVariant, including direct string resources.
LeadingIcon, TrailingIcon ImageVariant; the trailing icon is decorative, not a separate action.
Variant TextFieldVariant::Standard, Filled, or Outlined.
Align TextAlign within the editable viewport.
MaxLength std::size_t, counted in grapheme clusters for direct edits.
Validation Complete ValidationResult; does not filter suggestions.
InputConfiguration Complete TextInputConfiguration; multiline, secure, read-only, and newline-action settings are rejected.
EmptyContent Nonempty std::function<View()> producing non-interactive empty-state content.

Plain string-like suggestion ranges and initializer_list<StringVariant> use built-in text rows. Domain ranges use (value, range, text_factory, content_factory); the text factory must produce a StringVariant-compatible value and the content factory a View. Both forms accept a TextEditingValue or State-held value. Suggestion rows must not contain independent interactive controls.

Events, async suggestions, and empty results

Section titled “Events, async suggestions, and empty results”

OnChanged takes const TextEditingValue&; OnSelected takes std::size_t and const TextEditingValue&; OnSubmitted takes no arguments; OnExpandedChanged takes bool. Every callback runs on the UI thread and is bound to the current declaration. Popup visibility/highlight belongs to the component, so ExpandedChanged is an observation rather than a setter to feed back.

For server suggestions, update the complete editing value immediately, cancel the old search through TaskScope, and publish results only for the current query. An empty suggestion list is valid; provide EmptyContent if an open result surface should explain “No matches.” Do not replace an in-progress IME composition with a suggestion simply because a request completed.

The editor uses TextFieldStyle, including the chosen variant, caret, and validation. ComboBoxStyle owns only the popup: popup_background, foreground, active_item_background, item_padding, popup_padding, popup_shadow, minimum_item_height, maximum_popup_height, popup_corner_radii, and item_indication. The height limit bounds scrolling; it does not truncate the suggestion collection.