Combobox
Async-пошук без локальної фільтрації — компонент показує рівно те, що дійшло з сервера.
Відмінність від Select принципова: Select фільтрує свій статичний список
локально, Combobox — НІ. Панель показує рівно те, що споживач поклав в
options. Подвійна фільтрація (тут + сервером) ховала б валідні матчі,
які сервер знайшов за іншим полем.
Приклад
Обрано: —
API
Props
| Назва | Тип | Типово | Опис |
|---|---|---|---|
options* | ComboboxOption[] | — | Поточні варіанти. Компонент їх НЕ фільтрує: список приходить із сервера у відповідь на подію `search`. |
modelValue | string | number | — | Обране значення. Використовуйте через `v-model`. |
selectedLabel | string | — | Підпис поточного значення, поки його немає серед `options` — форма редагування до першого пошуку. Далі назву обраного компонент пам'ятає сам, навіть коли наступний пошук її вже не повертає. |
label | string | — | — |
placeholder | string | "Пошук…" | — |
size | FieldSize | "md" | Висота поля. На мобільному кожен розмір вищий за десктопний. |
error | string | — | Текст помилки. Сама його наявність вмикає стан помилки. |
hint | string | — | Підказка під полем. Ховається, коли показано помилку. |
name | string | — | — |
minChars | number | 0 | Не емітити `search`, доки запит коротший. 0 — емітити все. Короткий запит лише ховає панель — набраний текст лишається в полі. |
id | string | — | Стабільний DOM id. `name` використовується лише для форми. |
disabled | boolean | false | — |
required | boolean | — | — |
loading | boolean | false | Керований стан завантаження — панель показує «Завантаження…». |
clearable | boolean | true | Дозволяє скинути вибір хрестиком. |
mobileSheet | boolean | true | На вузькому екрані (до 768px) пошук і результати відкриваються нижнім sheet'ом на всю ширину замість випадайки під полем. |
Події
| Назва | Payload | Опис |
|---|---|---|
search | [query: string] | Введений текст. Споживач дебаунить і фетчить сам. |
update:modelValue | [value: string | number] | Обране значення або `null`, якщо вибір скинуто. |
Слоти
| Назва | Опис |
|---|---|
option | Власний рендер пункту списку. |
Доступно через ref
| Назва | Тип | Опис |
|---|---|---|
focus | () => void | Ставить фокус на поле. |
Коли використовувати
Вибір з ВЕЛИКИХ або віддалених наборів: користувачі, групи, моделі,
міста. minChars береже сервер від пошуку по одній букві: коротший запит
лише ховає панель, а набраний текст лишається в полі.
Значення поза поточними результатами
options тут — відповідь на ОСТАННІЙ пошук, а не довідник. Тож назву
обраного компонент запам'ятовує сам: новий пошук, що вже не повертає
обраний пункт, не стирає поле і не ховає хрестик.
Єдиний випадок, коли назву взяти нізвідки, — форма редагування до першого
пошуку: значення є, а options ще порожні. Для нього є selected-label:
<UiCombobox
v-model="cityId"
:options="results"
:selected-label="order.cityName"
@search="searchCities"
/>
Коли НЕ використовувати
Для статичного списку на 5–50 пунктів потрібен Select: локальна фільтрація миттєва й не коштує запитів.
Для мультивибору є MultiSelect.
На мобільному
До 768px поле стає кнопкою, а пошук і результати відкриваються нижнім sheet'ом фіксованої висоти, як у Select. Фокус одразу в полі пошуку — це автокомпліт, набір тексту тут єдиний спосіб вибору.
Запит у sheet'і окремий від тексту поля: під фоном і далі видно назву
обраного. Відкриття порожнього sheet'а віддає search(''), якщо попередній
запит був непорожнім (і minChars дорівнює 0), — інакше список лишився б
відфільтрованим запитом, якого в пошуку вже не видно. Запит коротший за
minChars не показує ні списку, ні «нічого не знайдено». Вимикається через
:mobile-sheet="false".
Доступність
Той самий ARIA-комбобокс, що в Select: role="combobox",
aria-autocomplete="list", панель — listbox, пункти — option з
aria-selected. Escape закриває панель і не «протікає» в модалку
навколо. Escape, Tab і клік поза полем скасовують недописаний запит —
у полі знову назва обраного.
Клік у поле лише відкриває панель: клік, яким переставляють каретку, не
закриває її разом із запитом. Закрити мишею — шевроном або кліком поза
полем. Атрибути, що не є props (aria-label, data-*), ідуть на саме поле.
Стан завантаження замінює шеврон спінером і показує «Завантаження…» в панелі — користувач розуміє, що пошук живий, а не зламався.