Listbox

Listbox — это компонент пользовательского интерфейса, предназначенный для выбора одного или нескольких значений из списка. В экосистеме SvelteKit UI-библиотек он играет ключевую роль при создании форм, фильтров, выпадающих списков и интерактивных панелей управления.

В отличие от стандартного <select>, Listbox предоставляет:

  • расширенные возможности стилизации
  • гибкое управление состоянием
  • поддержку кастомной логики выбора
  • лучшую интеграцию с реактивной моделью Svelte

Базовая структура Listbox

Типичная реализация Listbox строится из нескольких логических частей:

  • Контейнер (Root) — управляет состоянием и поведением
  • Кнопка/триггер (Button) — отображает текущее значение
  • Список (Options) — контейнер для элементов
  • Элемент (Option) — отдельный вариант выбора

Пример базовой структуры:

<script>
  import { Listbox } from '@rgossiaux/svelte-headlessui';

  let selected = 'apple';
  const items = ['apple', 'banana', 'orange'];
</script>

<Listbox bind:value={selected}>
  <Listbox.Button>
    {selected}
  </Listbox.Button>

  <Listbox.Options>
    {#each items as item}
      <Listbox.Option value={item}>
        {item}
      </Listbox.Option>
    {/each}
  </Listbox.Options>
</Listbox>

Реактивность и управление состоянием

Svelte предоставляет встроенную реактивность, что упрощает работу с Listbox:

$: selectedLabel = selected.toUpperCase();

Связывание через bind:value позволяет:

  • автоматически обновлять выбранное значение
  • синхронизировать UI и состояние
  • интегрироваться с формами

Кастомизация отображения

Listbox позволяет полностью контролировать рендеринг элементов через слоты:

<Listbox.Option value={item} let:active let:selected>
  <div class:selected={selected} class:active={active}>
    {item}
  </div>
</Listbox.Option>

Состояния:

  • active — элемент под курсором или в фокусе
  • selected — выбранный элемент

Поддержка клавиатуры и доступность

Listbox реализует стандарт WAI-ARIA:

  • Навигация стрелками ↑ ↓
  • Выбор через Enter / Space
  • Закрытие через Escape
  • Управление фокусом

Атрибуты доступности:

  • role="listbox"
  • role="option"
  • aria-selected

Это делает компонент доступным для screen reader’ов без дополнительной настройки.


Множественный выбор (Multiple Sel ect)

Listbox поддерживает выбор нескольких элементов:

<Listbox bind:value={selectedItems} multiple>

Где selectedItems — массив:

let selectedItems = [];

Логика выбора:

  • клик добавляет/удаляет элемент
  • состояние отслеживается автоматически

Стилизация

Поскольку большинство Svelte UI библиотек используют headless-подход, стили полностью на стороне разработчика.

Пример:

.option {
  padding: 8px;
  cursor: pointer;
}

.option.active {
  background: #eee;
}

.option.selected {
  font-weight: bold;
}

Анимации и переходы

Svelte позволяет легко добавлять анимации:

<script>
  import { fade } fr om 'svelte/transition';
</script>

<Listbox.Options transition:fade>

Также доступны:

  • fly
  • slide
  • кастомные transition-функции

Интеграция с формами

Listbox можно использовать как часть формы:

<form on:submit={handleSubmit}>
  <Listbox bind:value={selected} name="fruit">

Однако важно:

  • вручную сериализовать данные при необходимости
  • учитывать, что это не нативный <select>

Асинхронные данные

Listbox может работать с данными из API:

let items = [];

onMount(async () => {
  const res = await fetch('/api/items');
  items = await res.json();
});

Важно учитывать:

  • состояние загрузки
  • обработку ошибок
  • обновление списка

Оптимизация производительности

При большом количестве элементов:

  • использовать виртуализацию (например, svelte-virtual)
  • избегать лишних реактивных вычислений
  • мемоизировать данные

Расширенные паттерны

Кастомный фильтр (Searchable Listbox)

<input bind:value={query} placeholder="Поиск..." />

{#each items.filter(i => i.includes(query)) as item}

Группировка элементов

{#each groups as group}
  <div class="group">{group.name}</div>
  {#each group.items as item}

Отображение сложных объектов

const items = [
  { id: 1, name: 'Apple', icon: '?' }
];
<Listbox.Option value={item}>
  {item.icon} {item.name}
</Listbox.Option>

Сравнение с альтернативами

Компонент Особенности
<select> Нативный, ограниченный
Listbox Гибкий, настраиваемый
Combobox С поиском и вводом

Частые ошибки

  • Отсутствие уникальных value
  • Неправильная работа с массивами при multiple
  • Потеря фокуса при кастомных рендерах
  • Игнорирование доступности

Лучшие практики

  • Использовать headless-компоненты для гибкости
  • Разделять логику и представление
  • Добавлять визуальную обратную связь (hover, selected)
  • Поддерживать клавиатурную навигацию
  • Тестировать с screen reader

Архитектурные особенности

Listbox в SvelteKit часто строится на:

  • контексте (setContext, getContext)
  • реактивных переменных
  • слотах для композиции

Это обеспечивает:

  • переиспользуемость
  • масштабируемость
  • чистую архитектуру компонентов