Select
Select открывает плоский listbox с клавиатурной навигацией и typeahead. Метрики и визуал задаёт productScope.
Статус: stable · в системе с 2026-05 · интерактивность: always (всегда)
Когда использовать
- Короткий известный список нужно скрыть до запроса, чтобы экономить место.
- Основной label называет опцию, а короткая вторая строка при необходимости показывает ID или другой вспомогательный факт.
Не использовать:
- Две булевых опции «вкл/выкл».
- Варианты важно видеть все сразу — не прячь их в меню.
- Список длинный, часто меняется или требует поиска/фильтрации.
- Значение нельзя менять — покажи текст, а не интерактивный контрол.
Альтернативы:
switch— бинарное включение/выключениеradio— небольшой набор вариантов важно видеть и сравнивать сразуsegmented-control— короткие режимы переключают представление в одну строкуcombobox— одно значение из длинного плоского списка с поискомdualist— множественный выбор из длинного списка с поиском
Конструктор
Меняйте свойства Select, сочетайте их и проверяйте результат в одном живом экземпляре.
Базовый
Пункт меню может показывать короткую вторую строку; label остаётся текстом выбранного значения.
<script>
import { t } from "$lib/spec/demo-lang.svelte.js";
import Select from "$lib/ui/Select.svelte";
let city = $state("msk");
let role = $state("");
const cities = [
{ value: "msk", label: t("Москва"), description: "ID: msk" },
{ value: "spb", label: t("Санкт-Петербург"), description: "ID: spb" },
{ value: "nsk", label: t("Новосибирск"), description: "ID: nsk" },
{ value: "ekb", label: t("Екатеринбург"), description: "ID: ekb" },
];
const roles = [t("Дизайнер"), t("Разработчик"), t("Менеджер")];
</script>
<div style="display: grid; gap: var(--sp-3); width: var(--control-field-min);">
<Select label={t("Город")} options={cities} bind:value={city} />
<Select label={t("Роль")} options={roles} bind:value={role} />
</div>
Размеры
Канонические s / m; точные метрики задаёт productScope.
<script>
import { t } from "$lib/spec/demo-lang.svelte.js";
import Select from "$lib/ui/Select.svelte";
const cities = [
{ value: "msk", label: t("Москва") },
{ value: "spb", label: t("Санкт-Петербург") },
{ value: "nsk", label: t("Новосибирск") },
{ value: "ekb", label: t("Екатеринбург") },
];
</script>
<div style="display: grid; gap: var(--sp-3); width: var(--control-field-min);">
<Select size="s" label="Small" options={cities} value="msk" />
<Select size="m" label="Medium" options={cities} value="msk" />
</div>
Поле
Подсказка, описание, ошибка, обязательность.
<script>
import { t } from "$lib/spec/demo-lang.svelte.js";
import Select from "$lib/ui/Select.svelte";
let invalid = $state("");
const cities = [
{ value: "msk", label: t("Москва") },
{ value: "spb", label: t("Санкт-Петербург") },
{ value: "nsk", label: t("Новосибирск") },
{ value: "ekb", label: t("Екатеринбург") },
];
</script>
<div style="display: grid; gap: var(--sp-3); width: var(--control-field-min);">
<Select label={t("С подсказкой")} options={cities} hint={t("Выберите из списка")} />
<Select label={t("Обязательное")} options={cities} name="city" required />
<Select label={t("С описанием")} options={cities} description={t("Поясняющий текст под полем.")} />
<Select label={t("Город")} options={cities} bind:value={invalid} error={t("Выберите город")} />
</div>
Группы
Маркер { group } в options открывает группу; collapsible сворачивает её кликом по заголовку.
<!--
🟢
Группы пунктов (эталон: Vue-легаси select `item.group`): маркер `{ group }`
в options открывает группу капслоком, `collapsible` сворачивает её кликом
по заголовку с шевроном.
-->
<script>
import { t } from "$lib/spec/demo-lang.svelte.js";
import Select from "$lib/ui/Select.svelte";
const options = [
{ group: t("Поиск") },
{ value: "brand", label: t("Брендовый поиск") },
{ value: "generic", label: t("Общие запросы") },
{ group: t("Сети") },
{ value: "banner", label: t("Баннеры"), description: t("РСЯ и партнёры") },
{ value: "video", label: t("Видео") },
];
let value = $state("banner");
</script>
<div style="width: 320px;">
<Select label={t("Тип кампании")} {options} bind:value collapsible />
</div>
Очистка
clearable: крестик слева от стрелки сбрасывает значение и зовёт onclear.
<!--
🟢
Очистка значения (эталон: Vue-легаси select `clearable`): крестик слева
от стрелки сбрасывает выбор и зовёт onclear; сброшенное поле показывает
подпись в покое.
-->
<script>
import { t } from "$lib/spec/demo-lang.svelte.js";
import Select from "$lib/ui/Select.svelte";
const options = [
{ value: "active", label: t("Активные") },
{ value: "paused", label: t("На паузе") },
{ value: "archived", label: t("В архиве") },
];
let value = $state("active");
let cleared = $state(0);
</script>
<div style="display: flex; align-items: center; gap: var(--sp-2);">
<div style="width: 240px;">
<Select label={t("Статус")} {options} bind:value clearable onclear={() => (cleared += 1)} />
</div>
<span aria-live="polite">{value ? `${t("Выбрано:")} ${value}` : t("Не выбрано")}{cleared ? `${t(", очисток:")} ${cleared}` : ""}</span>
</div>