Docs

Documentation versions (currently viewingVaadin 24)

Combo Box

Combo Box allows the user to choose a value from a filterable list of options presented in an overlay.

Combo Box allows the user to choose a value from a filterable list of options presented in an overlay. It supports lazy loading and can be configured to accept custom typed values.

Open in a
new tab
ComboBox<Country> comboBox = new ComboBox<>("Country");
comboBox.setItems(DataService.getCountries());
comboBox.setItemLabelGenerator(Country::getName);
add(comboBox);

The overlay opens when the user clicks the field using a pointing device. Using the Up/Down arrow keys or typing a character — found in at least one of the options — when the field is focused also opens the popup.

Custom Value Entry

Combo Box can be configured to allow entering custom values that aren’t included in the list of options.

Open in a
new tab
ComboBox<String> comboBox = new ComboBox<>("Browser");
comboBox.setAllowCustomValue(true);
add(comboBox);

Allowing custom entry is useful when you need to present the most common choices, but still give users the freedom to enter their own options.

Custom values can also be stored and added to the list of options:

Open in a
new tab
ComboBox<String> comboBox = new ComboBox<>("Browser");
comboBox.setAllowCustomValue(true);
comboBox.addCustomValueSetListener(e -> {
    String customValue = e.getDetail();
    items.add(customValue);
    comboBox.setItems(items);
    comboBox.setValue(customValue);
});
add(comboBox);

Custom Item Presentation

Items can be customized to display more information than a single line of text.

Open in a
new tab
ComboBox<Person> comboBox = new ComboBox<>("Choose doctor");
comboBox.setItems(filter, DataService.getPeople());
comboBox.setItemLabelGenerator(
        person -> person.getFirstName() + " " + person.getLastName());
comboBox.setRenderer(createRenderer());
comboBox.getStyle().set("--vaadin-combo-box-overlay-width", "16em");
add(comboBox);

...

// NOTE
// We are using inline styles here to keep the example simple.
// We recommend placing CSS in a separate style sheet and to
// encapsulating the styling in a new component.

private Renderer<Person> createRenderer() {
    StringBuilder tpl = new StringBuilder();
    tpl.append("<div style=\"display: flex;\">");
    tpl.append(
            "  <img style=\"height: var(--lumo-size-m); margin-right: var(--lumo-space-s);\" src=\"${item.pictureUrl}\" alt=\"Portrait of ${item.firstName} ${item.lastName}\" />");
    tpl.append("  <div>");
    tpl.append("    ${item.firstName} ${item.lastName}");
    tpl.append(
            "    <div style=\"font-size: var(--lumo-font-size-s); color: var(--lumo-secondary-text-color);\">${item.profession}</div>");
    tpl.append("  </div>");
    tpl.append("</div>");

    return LitRenderer.<Person> of(tpl.toString())
            .withProperty("pictureUrl", Person::getPictureUrl)
            .withProperty("firstName", Person::getFirstName)
            .withProperty("lastName", Person::getLastName)
            .withProperty("profession", Person::getProfession);
}

Use a custom filter to allow the user to search by the rendered properties. It’s recommended to make filtering case insensitive.

Item Class Names

Items can be styled dynamically, based on application logic and the data in the combo box, through custom class names.

Open in a
new tab
ComboBox<String> comboBox = new ComboBox<>("Fruit");
comboBox.setItems(List.of("Apple", "Banana", "Orange", "Pear"));
comboBox.setClassNameGenerator((item) -> {
    switch (item) {
    case "Apple":
        return "coral";
    case "Banana":
        return "gold";
    case "Orange":
        return "orange";
    case "Pear":
        return "yellowgreen";
    default:
        return "";
    }
});

Auto Open

The overlay opens automatically when the field is focused using a pointer (i.e., mouse or touch), or when the user types in the field. You can disable this so that the overlay opens only when the toggle button or the Up/Down arrow keys are pressed.

Open in a
new tab
ComboBox<Country> comboBox = new ComboBox<>("Country");
comboBox.setAutoOpen(false);
add(comboBox);

The width of the popup is, by default, the same width as the input field. The popup width can be overridden to any fixed width in cases where the default width is too narrow.

Open in a
new tab
ComboBox<Person> comboBox = new ComboBox<>("Employee");
comboBox.getStyle().set("--vaadin-combo-box-overlay-width", "350px");
add(comboBox);

Custom Filtering

Combo Box’s filtering, by default, is configured to show only items that contain the entered value:

Open in a
new tab
<ComboBox label="Country" itemLabelPath="name" itemValuePath="id" items={items.value} />

Custom filtering is also possible. For example, if you only want to show items that start with the user’s input you could do something like this:

Open in a
new tab
ComboBox<Country> comboBox = new ComboBox<>("Country");

ItemFilter<Country> filter = (country, filterString) -> country
        .getName().toLowerCase().startsWith(filterString.toLowerCase());
comboBox.setItems(filter, DataService.getCountries());

add(comboBox);

Basic Features

The following features, common to most input field components, are supported:

Label

The label is used to identify the input field. It supports plain-text content, and its length is limited to the width of the field. Helpers and Tooltips can be used to provide additional information that doesn’t fit into the label.

Visible labels are strongly recommended for all input fields. In cases where the built-in label cannot be used, an external element can be associated as the field’s label through the aria-labelledby attribute. Fields without any visible label should include an invisible label for assistive technologies with the aria-label attribute.

Helper

Helpers are used to provide additional information that the user may need to enter in the field, such as format requirements or explanations of the field’s purpose below the field.

A style variant is available for rendering the helper above the field.

In addition to plain text, helpers can contain components and HTML elements. However, complex and interactive content is likely to have accessibility issues.

Placeholder

The placeholder is text that’s displayed when the field is empty. Its primary purpose is to provide a short input hint (e.g., the expected format) in situations where a Helper cannot be used.

Placeholders should not be used as a replacement for a visible label. They can be mistaken for a manually entered value. See Label for alternatives to the built-in field label.

Tooltip

Tooltips are small text pop-ups displayed on hover, and on keyboard-focus. They can be used to provide additional information about a field. This can be useful in situations where an always visible Helper is not appropriate. Helpers are generally recommended in favor of tooltips, though, as they provide much better discoverability and mobile support. See the Tooltip documentation for more information.

Clear Button

The clear button — which is displayed when the field is not empty — clears the field’s current value. Although the button itself is not keyboard focusable, the clear action can be taken with the Esc key, when the field has focus. The clear button can be especially useful in search and filter fields, where users often need to clear the value. They’re less useful, however, in regular forms.

Prefix

A prefix element — rendered at the start of the field — can be used to display units, icons, and similar visual cues to the field’s purpose or format.

Prefix elements typically don’t work well with assistive technologies like screen readers. Therefore, the information communicated by them should also be conveyed through other means, such as in a Label, a Helper or through ARIA attributes on the field itself.

External & Invisible Labels (ARIA)

Visible labels are strongly recommended for all input fields. In situations where the built-in label cannot be used, an external element can be associated as the field’s label through its element id. Fields without any visible label should be provided an invisible label for assistive technologies like screen readers.

<!-- Associates external element as label: -->
<label id="external-label">This is the label</label>
<vaadin-combo-box accessible-name-ref="external-label">...

<!-- Invisible label for screen readers: -->
<vaadin-combo-box accessible-name="This is the label">...
Open in a
new tab
ComboBox<String> field = new ComboBox<>();
field.setLabel("Label");
field.setHelperText("Helper text");
field.setPlaceholder("Placeholder");
field.setTooltipText("Tooltip text");
field.setClearButtonVisible(true);
field.setPrefixComponent(VaadinIcon.SEARCH.create());

Validation

Combo Box provides a validation mechanism based on constraints. Constraints allow you to define criteria that the value must meet to be considered valid. Validation occurs typically when the user initiates a value change, for example by selecting an item from the overlay or through text input followed by Enter. If the value is invalid, the field is highlighted in red, and an error message appears underneath the input. Certain constraints, however, can proactively prevent users from entering characters that would result in an invalid value.

Below is a list of supported constraints with more detailed information:

Required

Required fields are marked with an indicator next to the label, and become invalid if their value is first entered and then cleared.

An instruction text at the top of the form explaining the required indicator is recommended. The indicator itself can be customized with the --lumo-required-field-indicator style property.

Allowed Characters

A separate single-character, regular expression can be used to restrict the characters that can be entered into the field. Characters that don’t match the expression are rejected. However, values set programmatically are not subject to this restriction, even if they contain disallowed characters.

Open in a
new tab
ComboBox<String> field = new ComboBox<>();
field.setRequiredIndicatorVisible(true);
field.setAllowedCharPattern("[A-Z]");
field.setI18n(new ComboBoxI18n()
        .setRequiredErrorMessage("Field is required"));
Note
Data Binding & Custom Validation
Flow and Hilla offer an advanced API called Binder that allows you to bind data and add custom validation rules for multiple fields, creating forms. You can learn more about Binder from the corresponding Flow and Hilla articles.